pagetree.py :  » Content-Management-Systems » PyLucid » PyLucid_standalone » pylucid_project » apps » pylucid » models » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Content Management Systems » PyLucid 
PyLucid » PyLucid_standalone » pylucid_project » apps » pylucid » models » pagetree.py
# coding: utf-8

"""
    PyLucid models
    ~~~~~~~~~~~~~~

    Last commit info:
    ~~~~~~~~~~~~~~~~~
    $LastChangedDate: $
    $Rev: $
    $Author: $

    :copyleft: 2009 by the PyLucid team, see AUTHORS for more details.
    :license: GNU GPL v3 or above, see LICENSE for more details.
"""

import sys
from xml.sax.saxutils import escape

from django.db import models
from django.conf import settings
from django.core.cache import cache
from django.contrib.auth.models import Group
from django.contrib.sites.models import Site
from django.utils.safestring import mark_safe
from django.core.exceptions import ValidationError
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy
from django.contrib.sites.managers import CurrentSiteManager

# http://code.google.com/p/django-tools/
from django_tools.middlewares import ThreadLocal
from django_tools import model_utils

from pylucid_project.apps.pylucid.tree_model import BaseTreeModel,TreeGenerator
from pylucid_project.apps.pylucid.models.base_models import BaseModel,BaseModelManager,UpdateInfoBaseModel


TAG_INPUT_HELP_URL = \
"http://google.com/search?q=cache:django-tagging.googlecode.com/files/tagging-0.2-overview.html#tag-input"



class PageTreeManager(BaseModelManager):
    """
    Manager class for PageTree model

    inherited from models.Manager:
        get_or_create() method, witch expected a request object as the first argument.
    """
    def filter_accessible(self, queryset, user):
        """ filter all pages with can't accessible for the given user """

        if user.is_anonymous():
            # Anonymous user are in no user group
            return queryset.filter(permitViewGroup__isnull=True)

        if user.is_superuser:
            # Superuser can see everything ;)
            return queryset

        # filter pages for not superuser and not anonymous

        user_groups = user.groups.values_list('pk', flat=True)

        if not user_groups:
            # User is in no group
            return queryset.filter(permitViewGroup__isnull=True)

        # Filter out all view group
        return queryset.filter(
            models.Q(permitViewGroup__isnull=True) | models.Q(permitViewGroup__in=user_groups)
        )

    def all_accessible(self, user=None, filter_showlinks=False):
        """ returns all pages that the given user can access. """
        if user == None:
            user = ThreadLocal.get_current_user()

        queryset = self.model.on_site.order_by("position")
        queryset = self.filter_accessible(queryset, user)

        if filter_showlinks:
            # Filter PageTree.showlinks
            queryset = queryset.filter(showlinks=True)

        return queryset

    def get_tree(self, user=None, filter_showlinks=False, exclude_plugin_pages=False, exclude_extras=None):
        """ return a TreeGenerator instance with all accessable page tree instance """
        queryset = self.all_accessible(user, filter_showlinks)

        if exclude_plugin_pages:
            queryset = queryset.exclude(page_type=PageTree.PLUGIN_TYPE)
        if exclude_extras:
            queryset = queryset.exclude(**exclude_extras)

        items = queryset.values("id", "parent", "slug")
        tree = TreeGenerator(items, skip_no_parent=True)
        return tree

    def get_choices(self, user=None, exclude_extras=None):
        """ returns a choices list for e.g. a forms select widget. """
        tree = PageTree.objects.get_tree(user, exclude_plugin_pages=True, exclude_extras=exclude_extras)
        choices = [("", "---------")] + [
            (node.id, node.get_absolute_url()) for node in tree.iter_flat_list()
        ]
        return choices

    def get_root_page(self, user, filter_parent=True):
        """ returns the 'first' root page tree entry witch the user can access """
        queryset = self.all_accessible(user)

        if filter_parent:
            # All "root" pages
            queryset = queryset.filter(parent=None)
        else:
            # fallback if no "root" page is accessable
            queryset = queryset.order_by("parent", "position")

        try:
            return queryset[0]
        except IndexError, err:
            if self.model.on_site.count() == 0:
                raise PageTree.DoesNotExist("There exist no PageTree items! Have you install PyLucid?")
            elif filter_parent == True:
                # If all root pages not accessible for the current user
                # -> try to get the first accessable page
                return self.get_root_page(user, filter_parent=False)
            else:
                raise

    def get_pagemeta(self, request, pagetree, show_lang_errors=True):
        """
        retuns the PageMeta instance witch associated to the given >pagetree< instance.
        
        dissolving language in client favored languages
        if not exist:
            return system default language
            
        If show_lang_errors==True:
            create a page_msg if PageMeta doesn't exist in client favored language.
        """
        from pylucid_project.apps.pylucid.models import PageMeta# against import loops.

        # client favored Language instance:
        lang_entry = request.PYLUCID.current_language

        if pagetree.page_type == pagetree.PLUGIN_TYPE:
            # Automatic create a not existing PageMeta on PluginPages
            pagemeta = PageMeta.objects.verbose_get_or_create(
                request, pagetree, lang_entry, show_lang_errors=show_lang_errors
            )
            return pagemeta

        queryset = PageMeta.objects.filter(pagetree=pagetree)
        pagemeta, tried_languages = self.get_by_prefered_language(request, queryset)

        if pagemeta is None:
            # This page doesn't exist in any languages???
            raise

        if tried_languages and show_lang_errors:
            request.page_msg.error(
                _(
                    "PageMeta %(slug)s doesn't exist in client"
                    " favored language %(tried_languages)s,"
                    " use %(used_code)s entry."
                ) % {
                    "slug": pagetree.slug,
                    "tried_languages": ", ".join([l.description for l in tried_languages]),
                    "used_code": pagemeta.language.description,
                }
            )

        return pagemeta


    def get_page_from_url(self, request, url_path):
        """
        returns a tuple the page tree instance from the given url_path
        XXX: move it out from model?
        """
        if not request.user.is_superuser:
            user_groups = request.user.groups.all()

        path = url_path.strip("/").split("/")
        page = None
        for no, page_slug in enumerate(path):
            if slugify(page_slug) != page_slug.lower():
                raise PageTree.DoesNotExist("url part %r is not slugify" % page_slug)

            try:
                page = PageTree.on_site.get(parent=page, slug=page_slug)
            except PageTree.DoesNotExist:
                etype, evalue, etb = sys.exc_info()
                evalue = etype("Wrong url %r: %s" % (page_slug, evalue))
                raise etype, evalue, etb

            page_view_group = page.permitViewGroup

            # Check permissions
            if request.user.is_anonymous():
                # Anonymous user are in no user group
                if page_view_group != None:
                    # XXX: raise permission deny?
                    msg = "Permission deny"
                    if settings.DEBUG:
                        msg += " (url part: %s)" % escape(page_slug)
                    raise PageTree.DoesNotExist(msg)
            elif not request.user.is_superuser: # Superuser can see everything ;)
                if (page_view_group != None) and (page_view_group not in user_groups):
                    msg = "Permission deny"
                    if settings.DEBUG:
                        msg += " (not in view group %r, url part: %r)" % (page_view_group, escape(page_slug))
                    raise PageTree.DoesNotExist(msg)

            if page.page_type == PageTree.PLUGIN_TYPE:
                # It's a plugin
                prefix_url = "/".join(path[:no + 1])
                rest_url = "/".join(path[no + 1:])
#                if not rest_url.endswith("/"):
#                    rest_url += "/"
                return (page, prefix_url, rest_url)

        return (page, None, None)

    def get_backlist(self, request, pagetree=None):
        """
        Generate a list of backlinks, usefull for generating a "You are here" breadcrumb navigation.
        TODO: filter showlinks and permit settings
        TODO: filter current site
        FIXME: Think this created many database requests
        """
        if pagetree == None:
            pagetree = request.PYLUCID.pagetree

        pagemeta = self.get_pagemeta(request, pagetree, show_lang_errors=False)
        url = pagemeta.get_absolute_url()
        page_name = pagemeta.get_name()
        page_title = pagemeta.get_title()

        backlist = [{"url": url, "name": page_name, "title": page_title}]

        parent = pagetree.parent
        if parent:
            # insert parent links
            backlist = self.get_backlist(request, parent) + backlist

        return backlist


class PageTree(BaseModel, BaseTreeModel, UpdateInfoBaseModel):
    """
    The CMS page tree

    inherited attributes from TreeBaseModel:
        parent
        position

    inherited attributes from UpdateInfoBaseModel:
        createtime     -> datetime of creation
        lastupdatetime -> datetime of the last change
        createby       -> ForeignKey to user who creaded this entry
        lastupdateby   -> ForeignKey to user who has edited this entry
    """
    PAGE_TYPE = 'C'
    PLUGIN_TYPE = 'P'

    TYPE_CHOICES = (
        (PAGE_TYPE, 'CMS-Page'),
        (PLUGIN_TYPE , 'PluginPage'),
    )
    TYPE_DICT = dict(TYPE_CHOICES)

    objects = PageTreeManager()

    slug = models.SlugField(unique=False, help_text="(for building URLs)")

    site = models.ForeignKey(Site, default=Site.objects.get_current)
    on_site = CurrentSiteManager()

    page_type = models.CharField(max_length=1, choices=TYPE_CHOICES)

    design = models.ForeignKey("pylucid.Design", help_text="Page Template, CSS/JS files")

    showlinks = models.BooleanField(default=True,
        help_text="Accessable for all users, but don't put a Link to this page into menu/sitemap etc."
    )
    permitViewGroup = models.ForeignKey(Group, related_name="%(class)s_permitViewGroup",
        help_text="Limit viewable to a group?",
        null=True, blank=True,
    )
    permitEditGroup = models.ForeignKey(Group, related_name="%(class)s_permitEditGroup",
        help_text="Usergroup how can edit this page.",
        null=True, blank=True,
    )

    def clean_fields(self, exclude):
        """
        We must call clean_slug() here, because it needs a queryset. 
        """
        # check if parent is the same entry: child <-> parent loop:
        super(PageTree, self).clean_fields(exclude)

        # Check if slug exist in the same sub tree:
        if "slug" not in exclude:
            queryset = PageTree.on_site.filter(slug=self.slug, parent=self.parent)

            # Exclude the current object from the query if we are editing an
            # instance (as opposed to creating a new one)
            if self.pk is not None:
                queryset = queryset.exclude(pk=self.pk)

            exists = queryset.count()
            if exists:
                if self.parent == None: # parent is the tree root
                    parent_url = "/"
                else:
                    parent_url = self.parent.get_absolute_url()

                msg = "Page '%s<strong>%s</strong>/' exists already." % (parent_url, self.slug)
                message_dict = {"slug": (mark_safe(msg),)}
                raise ValidationError(message_dict)

        # Check if parent page is a ContentPage, a plugin page can't have any sub pages!
        if "parent" not in exclude and self.parent is not None and self.parent.page_type != self.PAGE_TYPE:
            parent_url = self.parent.get_absolute_url()
            msg = _(
                "Can't use the <strong>plugin</strong> page '%s' as parent page!"
                " Please choose a <strong>content</strong> page."
            ) % parent_url
            message_dict = {"parent": (mark_safe(msg),)}
            raise ValidationError(message_dict)

    _url_cache = {}
    def get_absolute_url(self):
        """ absolute url *without* language code (without domain/host part) """
        if self.pk in self._url_cache:
            #print "PageTree url cache len: %s, pk: %s" % (len(self._url_cache), self.pk)
            return self._url_cache[self.pk]

        if self.parent:
            parent_shortcut = self.parent.get_absolute_url()
            url = parent_shortcut + self.slug + "/"
        else:
            url = "/" + self.slug + "/"

        self._url_cache[self.pk] = url
        return url

    def save(self, *args, **kwargs):
        """ reset PageMeta and PageTree url cache """
        from pagemeta import PageMeta# against import loops.

        self._url_cache.clear()
        PageMeta._url_cache.clear()
        cache.clear() # FIXME: This cleaned the complete cache for every site!
        return super(PageTree, self).save(*args, **kwargs)

    def get_site(self):
        """ used e.g. for self.get_absolute_uri() and the admin page """
        return self.site

    def __unicode__(self):
        return u"PageTree %r (id: %i, site: %s, type: %s)" % (
            self.slug, self.id, self.site.domain, self.TYPE_DICT.get(self.page_type)
        )

    class Meta:
        app_label = 'pylucid'
        verbose_name_plural = verbose_name = "PageTree"
        unique_together = (("site", "slug", "parent"),)

        # FIXME: It would be great if we can order by get_absolute_url()
#        ordering = ("site", "id", "position")
        ordering = ("-lastupdatetime",)


# Check Meta.unique_together manually
model_utils.auto_add_check_unique_together(PageTree)


www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.