gnocchi-cms / gnocchi / cms / models.py

funkybob 995433e 





funkybob 1bc45c3 
funkybob e82dcce 
funkybob 995433e 







Alexander Nordlu… 3ffc236 


funkybob 995433e 











Alexander Nordlu… 3ffc236 

funkybob 995433e 


funkybob 1bc45c3 

funkybob 995433e 


















funkybob 92c4b54 
funkybob 995433e 








Alexander Nordlu… 3ffc236 

funkybob 995433e 


funkybob d53ed3b 
funkybob 995433e 





















funkybob e82dcce 


funkybob 94eba64 
funkybob e82dcce 






funkybob 995433e 















funkybob e82dcce 


funkybob 995433e 





















Alexander Nordlu… 3ffc236 

funkybob 995433e 



























Alexander Nordlu… 3ffc236 


funkybob 995433e 



funkybob 4ff0a45 

funkybob 995433e 

































Alexander Nordlu… 64108f7 


funkybob 995433e 


















from django.db import models
from django.contrib.contenttypes import generic
from django.utils.safestring import mark_safe
from django.utils import simplejson
from django.core.validators import RegexValidator, ValidationError
from django.core.urlresolvers import reverse
from django.template import Template as DjangoTemplate
from django.template.loader import get_template

# Used to clear cache on change
from django.db.models.signals import post_save
from gnocchi.cms import settings
from django.core.cache import cache

from gnocchi.tools.attr import AttrHelper

# Translations
from django.utils.translation import ugettext_lazy as _

#
# DB stored templates
#

class Template(models.Model):
    '''A Database backed Template'''
    path = models.CharField(max_length=500, db_index=True,
        help_text='This is NOT a URL')
    description = models.CharField(max_length=200, blank=True)
    content = models.TextField()

    class Meta:
        verbose_name = _('template')
        verbose_name_plural = _('templates')
        ordering = ('path',)
    def __unicode__(self):
        return self.path
    def render(self, context):
        return DjangoTemplate(self.content).render(context)

#
# URL tree model
#

class PageManager(models.Manager):
    def published(self):
        '''Filter for only published pages'''
        return self.get_query_set().filter(is_published=True)

class Page(models.Model, AttrHelper):
    '''Heirarchy of objects providing content'''
    parent = models.ForeignKey('self', blank=True, null=True,
        related_name='children')
    path = models.SlugField(blank=True,
        help_text = 'This will form part of the URL')
    title = models.CharField(max_length=512)

    is_published = models.BooleanField(default=True)
    order = models.PositiveIntegerField(default=0)

    template = models.ForeignKey(Template, blank=True, null=True)
    content = models.TextField(blank=True)

    attributes = generic.GenericRelation('tools.Attribute')

    objects = PageManager()

    class Meta:
        verbose_name = _('page')
        verbose_name_plural = _('pages')
        unique_together = (
            ('parent', 'path',),
        )
        ordering = ('order',)

    def _load_cache(self, force=False):
        if not hasattr(self, '_attributes') or force:
            self._attributes = dict(
                self.attributes.values_list('name', 'value')
            )
            self._attributes.update(dict(
                self.fragment_set.values_list('name', 'content')
            ))

    def __unicode__(self):
        return u'[%s] %s' % (self.get_absolute_url(), self.title,)

    def get_absolute_url(self):
        paths = [self.path, ]
        node = self.parent
        while node:
            paths.insert(0, node.path)
            node = node.parent
        return '/%s' % '/'.join(paths)
    get_absolute_url.short_description = 'url'

    def get_template(self):
        '''Returns the template to render this page'''
        if self.template_id:
            return self.template
        elif self.parent_id:
            return self.parent.get_template()
        return get_template(settings.DEFAULT_TEMPLATE)

    ##
    ## Tree-related functions
    ##
    def is_root(self):
        '''Return True if this is a root Page'''
        return self.parent == None

    def get_root(self):
        '''Find the root of this Page'''
        node = self
        while node.parent:
            node = node.parent
        return node

    @classmethod
    def get_all_roots(cls):
        '''Helper function to get all root pages'''
        return Page.objects.published().filter(parent=None)

    ##
    ## Permissions hook
    ##
    def can_view(self, user):
        '''Test if a User has permission to view this page.'''
        if user.is_authenticated():
            if user.is_staff:
                return True
            try:
                return self.pageaccess_set.get(group__user=user).permit
            except PageAccess.DoesNotExist:
                pass

        try:
            return self.pageaccess_set.get(group=None).permit
        except PageAccess.DoesNotExist:
            # No explicit rule == Permit
            return True

class Fragment(models.Model):
    '''Content fragment of a Page'''
    page = models.ForeignKey(Page)
    name = models.CharField(max_length=200)
    content = models.TextField(blank=True)
    class Meta:
        verbose_name = _('fragment')
        verbose_name_plural = _('fragments')
        unique_together = (
            ('page', 'name',)
        )

class PageAccess(models.Model):
    page = models.ForeignKey(Page)
    # who does this apply to?
    group = models.ForeignKey('auth.Group', null=True, blank=True)
    # What do we say?
    permit = models.BooleanField(default=True)

    def __unicode__(self):
        return u'Access for %s to %s' % (self.group or 'Default', self.page)
    class Meta:
        unique_together = (
            ('page', 'group',),
        )
        ordering = ('group',)

#
# Style Sheets
#

class StyleSheet(models.Model):
    '''Helpful wrapper for DB stored StyleSheets with Templating'''
    name = models.SlugField()
    description = models.CharField(max_length=1024, blank=True)
    content = models.TextField(blank=True)
    class Meta:
        verbose_name = _('style sheet')
        verbose_name_plural = _('style sheets')
    def __unicode__(self):
        return u'[%s] %s' % (self.name, self.description,)
    def get_absolute_url(self):
        return reverse('gnocchi.cms.views.css', kwargs={'name': self.name})
    def render(self, context):
        return DjangoTemplate(self.content).render(context)

#
# Global context variables
#

class ContextVariable(models.Model):
    TYPE_CHOICES = (
        ('str', 'Text',),
        ('bool', 'Boolean',),
        ('int', 'Integer',),
        ('float', 'Number',),
        ('json', 'JSON',),
    )
    # functions to convert from storage
    LOAD_MAP = {
        'bool': bool,
        'int': int,
        'float': float,
        'str': mark_safe,
        'json': simplejson.loads
    }
    # functions to convert to storage [default: unicode()]
    STORE_MAP = {
        'json': simplejson.dumps
    }
    name = models.CharField(max_length=64, validators=[
        RegexValidator(r'^\w+$'),
    ])
    group = models.CharField(max_length=64, validators=[
        RegexValidator(r'^\w+$'),
    ])
    description = models.CharField(max_length=200, blank=True)
    type = models.CharField(max_length=32, choices = TYPE_CHOICES)
    value = models.CharField(max_length=1024)
    class Meta:
        verbose_name = _('context variable')
        verbose_name_plural = _('context variables')
    def clean(self):
        try:
            self.get_value()
        except Exception, e:
            raise ValidationError, "Value %r not valid for type %s (%r)" % (
                self.value, self.type, e
            )
        if not isinstance(self.value, basestring):
            self.value = self.set_value(self.value)

    def get_value(self):
        return self.LOAD_MAP.get(self.type, lambda x: x)(self.value)
    def set_value(self, value):
        return self.STORE_MAP.get(self.type, unicode)(value)
    def full_name(self):
        return u'%s.%s' % (self.group, self.name,)

def cv_clear_cache(sender, **kwargs):
    cache.delete('gnocchi-%s' % settings.CV_NAMESPACE)
post_save.connect(cv_clear_cache, sender=ContextVariable)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.