Ejemplo n.º 1
0
class Question(models.Model):
    SEPARATOR = '\x01'

    quiz = CachedForeignKey(Quiz)
    order = models.PositiveIntegerField()

    photo = CachedForeignKey(Photo,
                             blank=True,
                             null=True,
                             on_delete=models.SET_NULL)
    text = models.TextField()

    choices_data = models.TextField()

    class Meta:
        unique_together = ((
            'quiz',
            'order',
        ), )

    def clean(self):
        if len(self.choices) != self.quiz.choices:
            raise ValidationError('Number of choices must match the Quiz.')

    def get_choices(self):
        # TODO: maybe a SortedDict would be better?
        return map(lambda ch: Choice(*ch),
                   enumerate(self.choices_data.split(self.SEPARATOR)))

    def set_choices(self, choices):
        self.choices_data = self.SEPARATOR.join(
            map(itemgetter(1), sorted(choices)))

    choices = property(get_choices, set_choices)
Ejemplo n.º 2
0
Archivo: main.py Proyecto: skada/ella
class Author(models.Model):
    """
    Describes an Author of the published content. Author can be:

    * Human
    * Organization
    * ...

    All the fields except for ``slug`` are optional to enable maximum of
    flexibility.
    """
    user = CachedForeignKey(User,
                            verbose_name=_('User'),
                            blank=True,
                            null=True)
    name = models.CharField(_('Name'), max_length=200, blank=True)
    slug = models.SlugField(_('Slug'),
                            max_length=255,
                            unique=True,
                            validators=[validate_slug])
    description = models.TextField(_('Description'), blank=True)
    text = models.TextField(_('Text'), blank=True)
    email = models.EmailField(_('Email'), blank=True)
    photo = CachedForeignKey('photos.Photo',
                             blank=True,
                             null=True,
                             on_delete=models.SET_NULL,
                             verbose_name=_('Photo'))

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

    def __unicode__(self):
        if not self.name:
            return self.slug
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('author_detail', [self.slug])

    def recently_published(self, **kwargs):
        if core_settings.USE_REDIS_FOR_LISTINGS:
            return redis.AuthorListingHandler(self)

        root = Category.objects.get_by_tree_path('')
        return root.app_data.ella.get_listings(children=ListingHandler.ALL,
                                               author=self,
                                               **kwargs)
Ejemplo n.º 3
0
class Listing(models.Model):
    """
    Listing of an ``Publishable`` in a ``Category``. Each and every object that have it's
    own detail page must have a ``Listing`` object that is valid (not expired) and
    places it in the object's main category. Any object can be listed in any
    number of categories (but only once per category). Even if the object is
    listed in other categories besides its main category, its detail page's url
    still belongs to the main one.
    """
    box_class = staticmethod(ListingBox)

    publishable = CachedForeignKey(Publishable, verbose_name=_('Publishable'))
    category = CategoryForeignKey(verbose_name=_('Category'), db_index=True)

    publish_from = models.DateTimeField(_("Start of listing"), db_index=True)
    publish_to = models.DateTimeField(_("End of listing"),
                                      null=True,
                                      blank=True)

    commercial = models.BooleanField(
        _("Commercial"),
        default=False,
        help_text=_("Check this if the listing is of a commercial content."))

    objects = ListingManager()

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

    def __unicode__(self):
        try:
            return ugettext(u'%(pub)s listed in %(cat)s') % {
                'pub': self.publishable,
                'cat': self.category
            }
        except:
            return ugettext('Broken listing')

    def clean(self):
        if not self.publishable:
            return

        if self.publish_from and self.publish_from < self.publishable.publish_from:
            raise ValidationError(
                _('A publishable cannot be listed before it\'s published.'))

        if self.publishable.publish_to:
            if not self.publish_to or self.publish_to > self.publishable.publish_to:
                raise ValidationError(
                    _('A publishable cannot be listed longer than it\'s published.'
                      ))

    def get_absolute_url(self, domain=False):
        return self.publishable.get_absolute_url(domain)

    def get_domain_url(self):
        return self.get_absolute_url(domain=True)
Ejemplo n.º 4
0
Archivo: main.py Proyecto: Pheox/ella
class Author(models.Model):
    """
    Describes an Author of the published content. Author can be:

    * Human
    * Organization
    * ...

    All the fields except for ``slug`` are optional to enable maximum of 
    flexibility.
    """
    user = CachedForeignKey(User,
                            verbose_name=_('User'),
                            blank=True,
                            null=True)
    name = models.CharField(_('Name'), max_length=200, blank=True)
    slug = models.SlugField(_('Slug'),
                            max_length=255,
                            unique=True,
                            validators=[validate_slug])
    description = models.TextField(_('Description'), blank=True)
    text = models.TextField(_('Text'), blank=True)
    email = models.EmailField(_('Email'), blank=True)
    photo = CachedForeignKey('photos.Photo',
                             blank=True,
                             null=True,
                             on_delete=models.SET_NULL,
                             verbose_name=_('Photo'))

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

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('author_detail', [self.slug])

    def recently_published(self, **kwargs):
        Listing = get_model('core', 'Listing')
        return Listing.objects.get_listing(children=ListingHandler.ALL,
                                           publishable__authors__in=[self],
                                           **kwargs)
Ejemplo n.º 5
0
class Result(models.Model):
    quiz = CachedForeignKey(Quiz)
    choice = models.IntegerField()

    photo = CachedForeignKey(Photo,
                             blank=True,
                             null=True,
                             on_delete=models.SET_NULL)
    title = models.CharField(max_length=200)
    text = models.TextField()

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

    class Meta:
        unique_together = ((
            'quiz',
            'choice',
        ), )

    def get_absolute_url(self):
        return resolver.reverse(self.quiz, 'quiz-result', choice=self.choice)
Ejemplo n.º 6
0
Archivo: models.py Proyecto: whit/ella
class CategoryLock(models.Model):
    category = CachedForeignKey(Category,
                                verbose_name=_('Category'),
                                unique=True)
    password = models.CharField(_('Password'), max_length=255)

    class Meta:
        verbose_name = _('Category Lock')
        verbose_name_plural = _('Category Locks')

    def __unicode__(self):
        return u'Locked Category %s' % self.category

    def form(self, *args, **kwargs):
        return CategoryLockForm(*args, **kwargs)
Ejemplo n.º 7
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)