Exemple #1
0
class Dependency(models.Model):
    """
    Object dependency - model for recording dependent items. For example when we use photo in article content.
    """

    target_ct = models.ForeignKey(ContentType,
                                  related_name='dependency_for_set')
    target_id = models.IntegerField()
    target = CachedGenericForeignKey('target_ct', 'target_id')

    dependent_ct = models.ForeignKey(ContentType,
                                     related_name='depends_on_set')
    dependent_id = models.IntegerField()
    dependent = CachedGenericForeignKey('dependent_ct', 'dependent_id')

    def __unicode__(self):
        return u'%s depends on %s' % (self.dependent, self.target)

    class Meta:
        app_label = 'core'
        verbose_name = _('Dependency')
        verbose_name_plural = _('Dependencies')
        ordering = (
            'dependent_ct',
            'dependent_id',
        )
Exemple #2
0
class Related(models.Model):
    """
    Related objects - model for recording related ``Publishable`` objects.
    An example would be two articles sharing a similar topic. When something
    like this happens, a ``Related`` instance connecting the objects should
    be created.
    """
    publishable = models.ForeignKey(Publishable, verbose_name=_('Publishable'))

    related_ct = ContentTypeForeignKey(verbose_name=_('Content type'))
    related_id = models.IntegerField(_('Object ID'))
    related = CachedGenericForeignKey('related_ct', 'related_id')

    objects = RelatedManager()

    class Meta:
        app_label = 'core'
        verbose_name = _('Related')
        verbose_name_plural = _('Related')

    def __unicode__(self):
        return _(u'%(pub)s relates to %(rel)s') % {
            'pub': self.publishable,
            'rel': self.related
        }
Exemple #3
0
class Position(models.Model):
    " Represents a position on a page belonging to a certain category. "
    box_class = staticmethod(PositionBox)

    category = models.ForeignKey(Category, verbose_name=_('Category'))
    name = models.CharField(_('Name'), max_length=200)

    target_ct = models.ForeignKey(ContentType,
                                  verbose_name=_('Target content type'),
                                  null=True,
                                  blank=True)
    target_id = models.PositiveIntegerField(_('Target id'),
                                            null=True,
                                            blank=True)

    target = CachedGenericForeignKey('target_ct', 'target_id')

    active_from = models.DateTimeField(_('Position active from'),
                                       null=True,
                                       blank=True)
    active_till = models.DateTimeField(_('Position active till'),
                                       null=True,
                                       blank=True)

    box_type = models.CharField(_('Box type'), max_length=200, blank=True)
    text = models.TextField(_('Definition'), blank=True)
    disabled = models.BooleanField(_('Disabled'), default=False)

    objects = PositionManager()

    def render(self, context, nodelist, box_type):
        " Render the position. "
        if not self.target:
            if self.target_ct:
                # broken Generic FK:
                log.warning('Broken target for position with pk %r', self.pk)
                return ''
            try:
                return Template(self.text,
                                name="position-%s" % self.name).render(context)
            except TemplateSyntaxError, e:
                log.error('Broken definition for position with pk %r', self.pk)
                return ''

        if self.box_type:
            box_type = self.box_type
        if self.text:
            nodelist = Template('%s\n%s' % (nodelist.render({}), self.text),
                                name="position-%s" % self.name).nodelist

        b = self.box_class(self, box_type, nodelist)
        b.prepare(context)
        return b.render()
Exemple #4
0
class Dependency(models.Model):
    """
    Captures relations between objects to simplify finding out what other objects
    my object depend on.

    This sounds mysterious, but the common use case is quite simple: keeping
    information which objects have been embedded in article content using
    **boxes** for example (these might be photos, galleries, ...).
    """
    target_ct = ContentTypeForeignKey(related_name='dependency_for_set')
    target_id = models.IntegerField()
    target = CachedGenericForeignKey('target_ct', 'target_id')

    dependent_ct = ContentTypeForeignKey(related_name='depends_on_set')
    dependent_id = models.IntegerField()
    dependent = CachedGenericForeignKey('dependent_ct', 'dependent_id')

    class Meta:
        app_label = 'core'
        verbose_name = _('Dependency')
        verbose_name_plural = _('Dependencies')

    def __unicode__(self):
        return _(u'%(obj)s depends on %(dep)s') % {'obj': self.dependent, 'dep': self.target}
Exemple #5
0
class TemplateBlock(models.Model):
    template = models.ForeignKey(DbTemplate)
    name = models.CharField(_('Name'), max_length=200)
    box_type = models.CharField(_('Box type'), max_length=200, blank=True)
    target_ct = models.ForeignKey(ContentType, null=True, blank=True)
    target_id = models.IntegerField(null=True, blank=True)
    active_from = models.DateTimeField(_('Block active from'),
                                       null=True,
                                       blank=True)
    active_till = models.DateTimeField(_('Block active till'),
                                       null=True,
                                       blank=True)

    text = models.TextField(_('Definition'), blank=True)

    objects = TemplateBlockManager()

    target = CachedGenericForeignKey(ct_field="target_ct",
                                     fk_field="target_id")

    def get_text(self):
        text = []

        if self.box_type and self.target:
            text.append('{%% box %s for %s.%s with id %s %%}' %
                        (self.box_type, self.target_ct.app_label,
                         self.target_ct.model, self.target_id))

        text.append(self.text.strip())

        if self.box_type and self.target:
            text.append('{% endbox %}')

        return '\n'.join(text)

    class Meta:
        verbose_name = _('Template block')
        verbose_name_plural = _('Template blocks')
        # unique_together = (('template', 'name',),)
        unique_together = ((
            'template',
            'name',
            'active_from',
            'active_till',
        ), )

    def __unicode__(self):
        return '%s' % self.name
Exemple #6
0
class TotalRate(models.Model):
    """
    save all rating for individual object.
    """
    target_ct = models.ForeignKey(ContentType, db_index=True)
    target_id = models.PositiveIntegerField(_('Object ID'), db_index=True)
    target = CachedGenericForeignKey('target_ct', 'target_id')
    amount = models.DecimalField(_('Amount'), max_digits=10, decimal_places=2)

    objects = TotalRateManager()

    def __unicode__(self):
        return u'%s points for %s' % (self.amount, self.target)

    class Meta:
        verbose_name = _('Total rate')
        verbose_name_plural = _('Total rates')
Exemple #7
0
class Related(models.Model):
    """
    Related objects - model for recording related items. For example related articles.
    """
    publishable = models.ForeignKey(Publishable, verbose_name=_('Publishable'))

    related_ct = models.ForeignKey(ContentType, verbose_name=_('Content type'))
    related_id = models.IntegerField(_('Object ID'))
    related = CachedGenericForeignKey('related_ct', 'related_id')

    objects = RelatedManager()

    def __unicode__(self):
        return u'%s relates to %s' % (self.publishable, self.related)

    class Meta:
        app_label = 'core'
        verbose_name = _('Related')
        verbose_name_plural = _('Related')
Exemple #8
0
class Publishable(models.Model):
    """
    Base class for all objects that can be published in Ella.
    """
    box_class = staticmethod(PublishableBox)

    content_type = ContentTypeForeignKey(editable=False)
    target = CachedGenericForeignKey('content_type', 'id')

    category = CategoryForeignKey(verbose_name=_('Category'))

    # Titles
    title = models.CharField(_('Title'), max_length=255)
    slug = models.SlugField(_('Slug'),
                            max_length=255,
                            validators=[validate_slug])

    # Authors and Sources
    authors = models.ManyToManyField(Author, verbose_name=_('Authors'))
    source = CachedForeignKey(Source,
                              blank=True,
                              null=True,
                              verbose_name=_('Source'),
                              on_delete=models.SET_NULL)

    # Main Photo
    photo = CachedForeignKey('photos.Photo',
                             blank=True,
                             null=True,
                             on_delete=models.SET_NULL,
                             verbose_name=_('Photo'))

    # Description
    description = models.TextField(_('Description'), blank=True)

    # Publish data
    published = models.BooleanField(_('Published'))
    publish_from = models.DateTimeField(
        _('Publish from'),
        default=core_settings.PUBLISH_FROM_WHEN_EMPTY,
        db_index=True)
    publish_to = models.DateTimeField(_("End of visibility"),
                                      null=True,
                                      blank=True)
    static = models.BooleanField(_('static'), default=False)

    # Last updated
    last_updated = models.DateTimeField(_('Last updated'), blank=True)

    # generic JSON field to store app cpecific data
    app_data = AppDataField(default='{}', editable=False)

    # has the content_published signal been sent for this instance?
    announced = models.BooleanField(help_text='Publish signal sent',
                                    default=False,
                                    editable=False)

    objects = PublishableManager()

    class Meta:
        app_label = 'core'
        verbose_name = _('Publishable object')
        verbose_name_plural = _('Publishable objects')

    def __unicode__(self):
        return self.title

    def __eq__(self, other):
        return isinstance(other, Publishable) and self.pk == other.pk

    def get_absolute_url(self, domain=False):
        " Get object's URL. "
        category = self.category

        kwargs = {
            'slug': self.slug,
        }

        if self.static:
            kwargs['id'] = self.pk
            if category.tree_parent_id:
                kwargs['category'] = category.tree_path
                url = reverse('static_detail', kwargs=kwargs)
            else:
                url = reverse('home_static_detail', kwargs=kwargs)
        else:
            publish_from = localize(self.publish_from)
            kwargs.update({
                'year': publish_from.year,
                'month': publish_from.month,
                'day': publish_from.day,
            })
            if category.tree_parent_id:
                kwargs['category'] = category.tree_path
                url = reverse('object_detail', kwargs=kwargs)
            else:
                url = reverse('home_object_detail', kwargs=kwargs)

        if category.site_id != settings.SITE_ID or domain:
            return 'http://' + category.site.domain + url
        return url

    def get_domain_url(self):
        return self.get_absolute_url(domain=True)

    def clean(self):
        if self.static or not self.published:
            return

        # fields are missing, validating uniqueness is pointless
        if not self.category_id or not self.publish_from or not self.slug:
            return

        qset = self.__class__.objects.filter(
            category=self.category,
            published=True,
            publish_from__day=self.publish_from.day,
            publish_from__month=self.publish_from.month,
            publish_from__year=self.publish_from.year,
            slug=self.slug)

        if self.pk:
            qset = qset.exclude(pk=self.pk)

        if qset:
            raise ValidationError(
                _('Another %s already published at this URL.') %
                self._meta.verbose_name)

    def save(self, **kwargs):
        # update the content_type if it isn't already set
        if not self.content_type_id:
            self.content_type = ContentType.objects.get_for_model(self)
        send_signal = None
        old_self = None
        if self.pk:
            try:
                old_self = self.__class__.objects.get(pk=self.pk)
            except Publishable.DoesNotExist:
                pass

        if old_self:
            old_path = old_self.get_absolute_url()
            new_path = self.get_absolute_url()

            # detect change in URL and not a static one
            if old_path != new_path and new_path and not old_self.static:
                # and create a redirect
                redirect = Redirect.objects.get_or_create(
                    old_path=old_path, site=self.category.site)[0]
                redirect.new_path = new_path
                redirect.save(force_update=True)
                # also update all potentially already existing redirects
                Redirect.objects.filter(new_path=old_path).exclude(
                    pk=redirect.pk).update(new_path=new_path)

            # detect change in publication status
            if old_self.is_published() != self.is_published():
                if self.is_published():
                    send_signal = content_published
                    self.announced = True
                else:
                    send_signal = content_unpublished
                    self.announced = False

            # @note: We also need to check for `published` flag even if both
            # old and new self `is_published()` method returns false.
            # This method can report false since we might be in time *before*
            # publication should take place but we still need to fire signal
            # that content has been unpublished.
            if old_self.published != self.published and self.published is False:
                send_signal = content_unpublished
                self.announced = False

            # changed publish_from and last_updated was default, change it too
            if old_self.last_updated == old_self.publish_from and self.last_updated == old_self.last_updated:
                self.last_updated = self.publish_from

            #TODO: shift Listing in case publish_(to|from) changes
        # published, send the proper signal
        elif self.is_published():
            send_signal = content_published
            self.announced = True

        if not self.last_updated:
            self.last_updated = self.publish_from

        super(Publishable, self).save(**kwargs)

        if send_signal:
            send_signal.send(sender=self.__class__, publishable=self)

    def delete(self):
        url = self.get_absolute_url()
        Redirect.objects.filter(new_path=url).delete()
        if self.announced:
            content_unpublished.send(sender=self.__class__, publishable=self)
        return super(Publishable, self).delete()

    def is_published(self):
        "Return True if the Publishable is currently active."
        cur_time = now()
        return self.published and cur_time > self.publish_from and \
            (self.publish_to is None or cur_time < self.publish_to)
Exemple #9
0
class Position(models.Model):
    """
    Represents a position -- a placeholder -- on a page belonging to a certain
    category.
    """
    box_class = staticmethod(PositionBox)

    name = models.CharField(_('Name'), max_length=200)
    category = CategoryForeignKey(verbose_name=_('Category'))

    target_ct = ContentTypeForeignKey(verbose_name=_('Target content type'),
                                      null=True,
                                      blank=True)
    target_id = models.PositiveIntegerField(_('Target id'),
                                            null=True,
                                            blank=True)
    target = CachedGenericForeignKey('target_ct', 'target_id')
    text = models.TextField(_('Definition'), blank=True)
    box_type = models.CharField(_('Box type'), max_length=200, blank=True)

    active_from = models.DateTimeField(_('Position active from'),
                                       null=True,
                                       blank=True)
    active_till = models.DateTimeField(_('Position active till'),
                                       null=True,
                                       blank=True)
    disabled = models.BooleanField(_('Disabled'), default=False)

    objects = PositionManager()

    class Meta:
        verbose_name = _('Position')
        verbose_name_plural = _('Positions')

    def clean(self):
        if not self.category or not self.name:
            return

        if self.target_ct:
            try:
                get_cached_object(self.target_ct, pk=self.target_id)
            except self.target_ct.model_class().DoesNotExist:
                raise ValidationError(
                    _('This position doesn\'t point to a valid object.'))

        qset = Position.objects.filter(category=self.category, name=self.name)

        if self.pk:
            qset = qset.exclude(pk=self.pk)

        if self.active_from:
            qset = qset.exclude(active_till__lte=self.active_from)

        if self.active_till:
            qset = qset.exclude(active_from__gt=self.active_till)

        if qset.count():
            raise ValidationError(
                _('There already is a postion for %(cat)s named %(name)s fo this time.'
                  ) % {
                      'cat': self.category,
                      'name': self.name
                  })

    def __unicode__(self):
        return u'%s:%s' % (self.category, self.name)

    def render(self, context, nodelist, box_type):
        " Render the position. "
        if not self.target:
            if self.target_ct:
                # broken Generic FK:
                log.warning('Broken target for position with pk %r', self.pk)
                return ''
            try:
                return Template(self.text,
                                name="position-%s" % self.name).render(context)
            except TemplateSyntaxError:
                log.error('Broken definition for position with pk %r', self.pk)
                return ''

        if self.box_type:
            box_type = self.box_type
        if self.text:
            nodelist = Template('%s\n%s' % (nodelist.render({}), self.text),
                                name="position-%s" % self.name).nodelist

        b = self.box_class(self, box_type, nodelist)
        return b.render(context)