Revision: 611
Author: batiste.bieler
Date: Tue Jul 21 01:02:49 2009
Log: Apply the patch for URL aliasing
http://code.google.com/p/django-page-cms/source/detail?r=611

Modified:
  /trunk/pages/admin/__init__.py
  /trunk/pages/managers.py
  /trunk/pages/models.py
  /trunk/pages/templatetags/pages_tags.py
  /trunk/pages/urls.py
  /trunk/pages/utils.py
  /trunk/pages/views.py

=======================================
--- /trunk/pages/admin/__init__.py      Sat Jul 11 06:22:03 2009
+++ /trunk/pages/admin/__init__.py      Tue Jul 21 01:02:49 2009
@@ -14,7 +14,7 @@
  from django.contrib.admin.sites import AlreadyRegistered

  from pages import settings
-from pages.models import Page, Content
+from pages.models import Page, Content, PageAlias
  from pages.utils import has_page_add_permission, get_placeholders
  from pages.http import get_language_from_request, get_template_from_request

@@ -415,3 +415,12 @@
      except AlreadyRegistered:
          pass

+class AliasAdmin(admin.ModelAdmin):
+    list_display = ('page', 'url', 'is_canonical',)
+    list_editable = ('url', 'is_canonical',)
+
+try:
+    admin.site.register(PageAlias, AliasAdmin)
+except AlreadyRegistered:
+    pass
+
=======================================
--- /trunk/pages/managers.py    Sat Jul 11 07:24:12 2009
+++ /trunk/pages/managers.py    Tue Jul 21 01:02:49 2009
@@ -36,7 +36,8 @@
          return self.filter(parent__isnull=True)

      def valid_targets(self, page_id, perms="All", page=None):
-        """QuerySet of valid targets for moving a page into the tree"""
+        """return a ``QuerySet`` of valid targets for moving a page into  
the
+        tree"""
          if page is None:
              page = self.get(pk=page_id)
          exclude_list = []
@@ -145,7 +146,7 @@
          content = self.create(page=page, language=language, body=body,  
type=cnttype)

      def get_content(self, page, language, ctype, language_fallback=False):
-        """Gets the latest content for a particular page and language.
+        """Gets the latest ``Content`` for a particular page and language.
          Falls back to another language if wanted."""
          PAGE_CONTENT_DICT_KEY = "page_content_dict_%d_%s"
          if not language:
@@ -174,7 +175,7 @@
          return ''

      def get_content_slug_by_slug(self, slug):
-        """Returns the latest Content slug object that match the given
+        """Returns the latest ``Content`` slug object that match the given
          slug for the current site domain."""
          content = self.filter(type='slug', body=slug)
          if settings.PAGE_USE_SITE_ID:
@@ -187,7 +188,7 @@
              return content

      def get_page_ids_by_slug(self, slug):
-        """Return all the page id according to a slug."""
+        """Return all page id matching the given slug."""
          sql = '''SELECT pages_content.page_id,
              MAX(pages_content.creation_date)
              FROM pages_content WHERE (pages_content.type = %s
@@ -202,8 +203,8 @@
      """Hierachic page permission"""

      def get_page_id_list(self, user):
-        """Give a list of page where the user has rights or the  
string "All"
-        if the user has all rights."""
+        """Give a list of ``Page`` ids where the user has rights or the  
string
+        "All" if the user has all rights."""
          if user.is_superuser:
              return 'All'
          id_list = []
@@ -217,3 +218,43 @@
                      if page.id not in id_list:
                          id_list.append(page.id)
          return id_list
+
+class PageAliasManager(models.Manager):
+    """PageAlias manager"""
+    def get_for_url(self, request, path=None, lang=None):
+        """
+        resolve a request to an alias. returns a PageAlias object or None  
if the url
+        matches no page at all. The aliasing system supports plain aliases  
(/foo/bar)
+        as well as aliases containing GET parameters  
(like "index.php?page=foo").
+        """
+        from pages.utils import normalize_url
+        from pages.models import Page,PageAlias
+
+        url = normalize_url(path)
+        # §1: try with complete query string
+        if request.META["QUERY_STRING"]!="":
+            url = url + '?' + request.META["QUERY_STRING"]
+        try:
+            alias = PageAlias.objects.get(url=url)
+            return alias
+        except PageAlias.DoesNotExist:
+            pass
+        # §2: try with path only
+        url = normalize_url(path)
+        try:
+            alias = PageAlias.objects.get(url=url)
+            return alias
+        except PageAlias.DoesNotExist:
+            pass
+        # §3: the requested path is not an alias, but it may be the slug  
of a page
+        page = Page.objects.from_path(path, lang)
+        if page:
+            alias = PageAlias(page=page, url=path)
+            # we have a page, let's see if there is a canonical alias for  
it
+            if PageAlias.objects.filter(page=page,  
is_canonical=True).count()>0:
+                alias.is_canonical = False
+            else:
+                alias.is_canonical = True
+            return alias
+        else:
+            return None
=======================================
--- /trunk/pages/models.py      Wed Jul 15 01:56:17 2009
+++ /trunk/pages/models.py      Tue Jul 21 01:02:49 2009
@@ -25,7 +25,7 @@
  import mptt
  from pages import settings
  from pages.utils import get_placeholders
-from pages.managers import PageManager, ContentManager,  
PagePermissionManager
+from pages.managers import PageManager, ContentManager,  
PagePermissionManager, PageAliasManager


  class Page(models.Model):
@@ -157,10 +157,16 @@
          return languages

      def get_absolute_url(self, language=None):
-        url = reverse('pages-root')
-        if settings.PAGE_USE_LANGUAGE_PREFIX:
-            url += str(language) + '/'
-        return url + self.get_url(language)
+        try:
+            alias = PageAlias.objects.get(page=self, is_canonical=True)
+            #if settings.PAGE_USE_LANGUAGE_PREFIX:
+            #    url = str(language) + '/' + self.url
+            return alias.url
+        except:
+            url = reverse('pages-root')
+            if settings.PAGE_USE_LANGUAGE_PREFIX:
+                url += str(language) + '/'
+            return url + self.get_url(language)

      def get_url(self, language=None):
          """
@@ -313,3 +319,23 @@

      def __unicode__(self):
          return "%s :: %s" % (self.page.slug(), self.body[0:15])
+
+class PageAlias(models.Model):
+    """URL alias for a page"""
+    page = models.ForeignKey(Page, null=True, blank=True,  
verbose_name=_('page'))
+    url = models.CharField(max_length=1024, unique=True)
+    is_canonical = models.NullBooleanField(null=True, blank=True)
+    objects = PageAliasManager()
+    class Meta:
+        verbose_name_plural = _('Aliases')
+
+    def save(self, *args, **kwargs):
+        # normalize url
+        self.url = normalize_url(self.url)
+
+        # override to handle "is_canonical" properly
+        if self.is_canonical:
+            for alias in PageAlias.objects.filter(page=self.page):
+                alias.is_canonical = False
+                alias.save()
+        super(PageAlias, self).save(*args, **kwargs)
=======================================
--- /trunk/pages/templatetags/pages_tags.py     Sat Jul 11 06:22:03 2009
+++ /trunk/pages/templatetags/pages_tags.py     Tue Jul 21 01:02:49 2009
@@ -346,3 +346,30 @@
      return PlaceholderNode.handle_token(parser, token)

  register.tag('placeholder', do_placeholder)
+
+def pages_dynamic_tree_menu(context, page, url='/'):
+    """
+    render a "dynamic" tree menu, with all nodes expanded which are either
+    ancestors or the current page itself.
+    """
+    request = context['request']
+    site_id = None
+    children = None
+    if 'current_page' in context:
+        current_page = context['current_page']
+        # if this node is expanded, we also have to render its children
+        # a node is expanded if it is the current node or one of its  
ancestors
+        if page.lft <= current_page.lft and page.rght >= current_page.rght:
+            children = page.get_children_for_frontend()
+    return locals()
+
+pages_dynamic_tree_menu =  
register.inclusion_tag('pages/dynamic_tree_menu.html',
+                                                  
takes_context=True)(pages_dynamic_tree_menu)
+
+def pages_breadcrumb(context, page, url='/'):
+    request = context['request']
+    site_id = None
+    pages = page.get_ancestors()
+    return locals()
+pages_breadcrumb = register.inclusion_tag('pages/breadcrumb.html',
+                                                  
takes_context=True)(pages_breadcrumb)
=======================================
--- /trunk/pages/urls.py        Wed Jul 15 01:56:17 2009
+++ /trunk/pages/urls.py        Tue Jul 21 01:02:49 2009
@@ -1,6 +1,6 @@
  # -*- coding: utf-8 -*-
  from django.conf.urls.defaults import *
-from pages.views import details
+from pages.views import details, alias_wrapper
  from pages import settings

  urlpatterns = patterns('',
@@ -10,11 +10,11 @@

  if settings.PAGE_USE_LANGUAGE_PREFIX:
      urlpatterns += patterns('',
-        url(r'^(?P<lang>[-\w]+)/(?P<path>.*)$', details,
+        url(r'^(?P<lang>[-\w]+)/(?P<path>.*)$', alias_wrapper,
              name='pages-details-by-slug'),
      )
  else:
      urlpatterns += patterns('',
-        url(r'^(?P<path>.*)$', details,
+        url(r'^(?P<path>.*)$', alias_wrapper,
              name='pages-details-by-slug'),
      )
=======================================
--- /trunk/pages/utils.py       Mon Jul 20 23:57:02 2009
+++ /trunk/pages/utils.py       Tue Jul 21 01:02:49 2009
@@ -24,10 +24,10 @@
          context = {}
      temp.render(RequestContext(request, context))
      plist, blist = [], []
-    _placeholders_recursif(temp.nodelist, plist, blist)
+    placeholders_recursif(temp.nodelist, plist, blist)
      return plist

-def _placeholders_recursif(nodelist, plist, blist):
+def placeholders_recursif(nodelist, plist, blist):
      """Recursively search into a template node list for PlaceholderNode
      node."""
      # I needed to import make this lazy import to make the doc compile
@@ -84,3 +84,23 @@
          if permission == "All":
              return True
      return False
+
+def normalize_url(url):
+    """ return a normalized url with trailing and without leading slash
+
+     >>> normalize_url(None)
+     '/'
+     >>> normalize_url('/foo/bar')
+     '/foo/bar'
+     >>> normalize_url('foo/bar')
+     '/foo/bar'
+     >>> normalize_url('/foo/bar/')
+     '/foo/bar'
+    """
+    if not url or len(url)==0:
+        return '/'
+    if not url.startswith('/'):
+        url = '/' + url
+    if url.endswith('/'):
+        url = url[0:len(url)-1]
+    return url
=======================================
--- /trunk/pages/views.py       Wed Jul  8 15:12:40 2009
+++ /trunk/pages/views.py       Tue Jul 21 01:02:49 2009
@@ -3,7 +3,7 @@
  from django.shortcuts import get_object_or_404
  from django.contrib.sites.models import SITE_CACHE
  from pages import settings
-from pages.models import Page, Content
+from pages.models import Page, Content, PageAlias
  from pages.http import auto_render, get_language_from_request
  from pages.http import get_slug_and_relative_path

@@ -67,3 +67,15 @@
      }

  details = auto_render(details)
+
+def alias_wrapper(request, path=None, lang=None, *args, **kwargs):
+    """
+    a wrapper for details() which resolves aliases and canonicalizes URLs
+    """
+    alias = PageAlias.objects.get_for_url(request, path, lang)
+    if not alias:
+        raise Http404
+    if alias.is_canonical:
+        return details(request, alias.page.slug(), *args, **kwargs)
+    else:
+        return  
HttpResponsePermanentRedirect(alias.page.get_absolute_url(lang))

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pinax-updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/pinax-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to