[urlpublishing] ticket #25847, add nicer URLs to display list of blogentries per year, month and blog
authorSandrine Ribeau <sandrine.ribeau@logilab.fr>
Tue, 03 Nov 2009 21:29:29 -0800
changeset 137 f8b8124b7f24
parent 136 fd6633078fc5
child 138 a6692493e5c6
[urlpublishing] ticket #25847, add nicer URLs to display list of blogentries per year, month and blog
views.py
views/__init__.py
views/primary.py
views/secondary.py
views/urlpublishing.py
--- a/views.py	Tue Nov 03 09:44:56 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-"""Specific views for blogs
-
-:organization: Logilab
-:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from calendar import monthrange
-from datetime import datetime
-
-from logilab.mtconverter import xml_escape
-
-from cubicweb.schema import display_name
-from cubicweb.view import EntityView, StartupView
-from cubicweb.utils import UStringIO
-from cubicweb.selectors import paginated_rset, sorted_rset, implements
-from cubicweb.web import uicfg
-from cubicweb.web.htmlwidgets import BoxLink, BoxWidget
-from cubicweb.web.views import baseviews, primary, boxes, calendar, navigation
-
-uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
-uicfg.primaryview_section.tag_attribute(('Blog', 'rss_url'), 'hidden')
-uicfg.primaryview_section.tag_attribute(('BlogEntry', 'title'), 'hidden')
-uicfg.primaryview_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
-uicfg.primaryview_section.tag_subject_of(('BlogEntry', 'entry_of', '*'),
-                                         'relations')
-
-uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
-
-class BlogPrimaryView(primary.PrimaryView):
-    __select__ = implements('Blog')
-
-    def render_entity_attributes(self, entity):
-        super(BlogPrimaryView, self).render_entity_attributes(entity)
-        self.w('<a class="right" href="%s">%s <img src="%s" alt="%s"/></a>' % (
-            xml_escape(entity.rss_feed_url()), self.req._(u'subscribe'),
-            self.req.external_resource('RSS_LOGO_16'), self.req._('rss icon')))
-
-    def render_entity_relations(self, entity):
-        super(BlogPrimaryView, self).render_entity_relations(entity)
-        rset = entity.related('entry_of', 'object')
-        strio = UStringIO()
-        self.pagination(self.req, rset, strio.write, page_size=10)
-        self.wview('adaptedlist', rset, 'null')
-        self.w(strio.getvalue())
-
-    def render_entity_title(self, entity):
-        self.w(u'<h1>%s</h1>' % xml_escape(entity.dc_title()))
-
-class BlogEntryPrimaryView(primary.PrimaryView):
-    __select__ = implements('BlogEntry')
-    show_attr_label = False
-
-    def render_entity_relations(self, entity):
-        rset = entity.related('entry_of', 'subject')
-        if rset:
-            self.w(self.req._('blogged in '))
-            self.wview('csv', rset, 'null')
-
-
-class BlogEntryArchiveView(StartupView):
-    """control the view of a blog archive"""
-    id = 'blog_archive'
-    countrql = 'Any COUNT(B) WHERE B is BlogEntry, B creation_date >=  %(firstday)s, B creation_date <= %(lastday)s'
-
-    def represent(self, items, year, month):
-        """represent a single month entry"""
-        firstday = datetime(year, month, 1)
-        lastday = datetime(year, month, monthrange(year, month)[1])
-        rql = ('Any B, BD ORDERBY BD DESC '
-               'WHERE B is BlogEntry, B creation_date BD, '
-               'B creation_date >=  "%s", B creation_date <= "%s"' %
-                (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d')))
-        args = {'firstday':firstday, 'lastday':lastday}
-        nmb_entries = self.req.execute(self.countrql, args)[0][0]
-        label = u'%s %s [%s]' % (self.req._(calendar.MONTHNAMES[month-1]), year,
-                                 nmb_entries)
-        url = xml_escape(self.build_url('view', rql=rql))
-        link = u'<a href="%s" title="">%s</a>' % (url, label)
-        items.append( u'<li class="">%s</li>\n' % link )
-
-    def call(self, maxentries=None, **kwargs):
-        """display a list of entities by calling their <item_vid> view
-        """
-        rset = self.req.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD')
-
-        blogmonths = []
-        items = []
-        for (blogdate,) in rset:
-            year, month = blogdate.year, blogdate.month
-            if (year, month) not in blogmonths:
-                blogmonths.append( (year, month) )
-        if maxentries is None:
-            displayed_months = blogmonths
-            needmore = False
-        else:
-            needmore = len(blogmonths) > maxentries
-            displayed_months = blogmonths[:maxentries]
-        for year, month in displayed_months:
-            self.represent(items, year, month)
-        if needmore:
-            url = self.build_url('view', vid='blog_archive')
-            link = u'<a href="%s" title="">[see more archives]</a>' % url
-            items.append( u'<li class="">%s</li>\n' % link )
-        self.w(u'<div class="boxFrame">')
-        if items:
-            self.w(u'<div class="boxContent">\n')
-            self.w(u'<ul class="boxListing">')
-            self.w(''.join(items))
-            self.w(u'</ul>\n</div>\n')
-        self.w(u'</div>')
-
-
-class BlogEntryArchiveBox(boxes.BoxTemplate):
-    """blog side box displaying a Blog Archive"""
-    id = 'blog_archives_box'
-    title = _('boxes_blog_archives_box')
-    order = 35
-
-    def call(self, **kwargs):
-        """display blogs archive"""
-        # XXX turn into a selector
-        count_blogentry = self.req.execute('Any COUNT(B) WHERE B is BlogEntry')
-        if count_blogentry[0][0] > 0:
-            box = BoxWidget(self.req._(self.title), id=self.id, islist=False)
-            box.append(boxes.BoxHtml(self.view('blog_archive', None, maxentries=12)))
-            box.render(self.w)
-
-
-class BlogEntryListBox(boxes.BoxTemplate):
-    """display a box with latest blogs and rss"""
-    id = 'blog_latest_box'
-    title = _('blog_latest_box')
-    visible = True # enabled by default
-    order = 34
-
-    def call(self, view=None, **kwargs):
-        # XXX turn into a selector
-        rset = self.req.execute('Any X,T,CD ORDERBY CD DESC LIMIT 5 '
-                                'WHERE X is BlogEntry, X title T, '
-                                'X creation_date CD')
-        if not rset:
-            return
-        box = BoxWidget(self.req._(self.title), self.id, islist=True)
-        # TODO - get the date between brakets after link
-        # empty string for title argument to deactivate auto-title
-        for i in xrange(rset.rowcount):
-            entity = rset.get_entity(i, 0)
-            box.append(BoxLink(entity.absolute_url(), xml_escape(entity.dc_title())))
-        rqlst = rset.syntax_tree()
-        rqlst.set_limit(None)
-        rql = rqlst.as_string(kwargs=rset.args)
-        url = self.build_url('view', rql=rql, page_size=10)
-        box.append(BoxLink(url,  u'[%s]' % self.req._(u'see more')))
-        rss_icon = self.req.external_resource('RSS_LOGO_16')
-        # FIXME - could use rss_url defined as a property if available
-        rss_label = u'%s <img src="%s" alt="%s"/>' % (
-            self.req._(u'subscribe'), rss_icon, self.req._('rss icon'))
-        rss_url = self.build_url('view', vid='rss', rql=rql)
-        box.append(BoxLink(rss_url, rss_label))
-        box.render(self.w)
-
-
-## list views ##################################################################
-
-class BlogEntryAdaptedListView(baseviews.AdaptedListView):
-    __select__ = baseviews.AdaptedListView.__select__ & implements('BlogEntry')
-
-    def call(self, **kwargs):
-        self.req.add_css('cubes.blog.css')
-        super(BlogEntryAdaptedListView, self).call(**kwargs)
-
-class BlogEntryAdaptedListItemView(baseviews.AdaptedListItemView):
-    __select__ = baseviews.AdaptedListView.__select__ & implements('BlogEntry')
-    redirect_vid = 'blog'
-
-
-class BlogEntryBlogView(EntityView):
-    id = 'blog'
-    __select__ = implements('BlogEntry')
-
-    def cell_call(self, row, col):
-        entity = self.entity(row, col)
-        w = self.w
-        _ = self.req._
-        w(u'<div class="post">')
-        w(u'<h1>%s</h1>' % entity.view('incontext'))
-        w(u'%s ' % entity.postinfo_description())
-        creator = entity.creator
-        if creator:
-            vtitle = _('blog entries created by %s') % creator.name()
-            rql = 'Any X ORDERBY D DESC WHERE X is BlogEntry, X created_by Y, '\
-                  'Y eid %s, X creation_date D' % creator.eid
-            url = self.build_url('view', rql=rql, vtitle=vtitle, page_size=10)
-            w(u'%s <a title="%s" href="%s">%s</a>' % (
-                _('by'), xml_escape(vtitle), xml_escape(url), creator.name()))
-        w(u'<div class="entry">')
-        body = entity.printable_value('content')
-        w(body)
-        w(u'</div>')
-        w(u'<div class="postmetadata">%s</div>' % entity.view('post-reldata'))
-        w(u'</div>')
-
-
-class BlogEntryPostMetaData(EntityView):
-    id = 'post-reldata'
-    __select__ = implements('BlogEntry')
-
-    def cell_call(self, row, col):
-        entity = self.entity(row, col)
-        _ = lambda ertype, form='': display_name(self.req, ertype, form)
-        reldata = []
-        w = reldata.append
-        if 'comments' in self.schema and 'BlogEntry' in self.schema.rschema('comments').objects():
-            count = self.req.execute('Any COUNT(C) WHERE C comments B, B eid %(x)s',
-                                     {'x': entity.eid}, 'x')[0][0]
-            if count:
-                url = xml_escape(entity.absolute_url())
-                w(u'<a href="%s">%s %s</a>' % (url, count, _('Comment', 'plural')))
-            else:
-                w(u'%s %s' % (count, _('Comment')))
-        if 'tags' in self.schema and 'BlogEntry' in self.schema.rschema('tags').objects():
-            tag_rset = entity.related('tags', 'object')
-            if tag_rset:
-                w(u'%s %s' % (_('tags', 'object'), self.view('csv', tag_rset)))
-        rset = entity.related('entry_of', 'subject')
-        if rset:
-            w(u'%s %s' % (self.req._('blogged in '),
-                          self.view('csv', rset, 'null')))
-        self.w(u' | '.join(reldata))
-
-
-class BlogNavigation(navigation.PageNavigation):
-    __select__ = paginated_rset() & sorted_rset() & implements('BlogEntry')
-
-    def index_display(self, start, stop):
-        return u'%s' % (int(start / self.page_size)+1)
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/primary.py	Tue Nov 03 21:29:29 2009 -0800
@@ -0,0 +1,54 @@
+"""Primary views for blogs
+
+:organization: Logilab
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+
+from logilab.mtconverter import xml_escape
+
+from cubicweb.utils import UStringIO
+from cubicweb.selectors import implements
+from cubicweb.web import uicfg
+from cubicweb.web.views import primary
+
+uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
+uicfg.primaryview_section.tag_attribute(('Blog', 'rss_url'), 'hidden')
+uicfg.primaryview_section.tag_attribute(('BlogEntry', 'title'), 'hidden')
+uicfg.primaryview_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
+uicfg.primaryview_section.tag_subject_of(('BlogEntry', 'entry_of', '*'),
+                                         'relations')
+
+uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
+
+class BlogPrimaryView(primary.PrimaryView):
+    __select__ = implements('Blog')
+
+    def render_entity_attributes(self, entity):
+        super(BlogPrimaryView, self).render_entity_attributes(entity)
+        self.w('<a class="right" href="%s">%s <img src="%s" alt="%s"/></a>' % (
+            xml_escape(entity.rss_feed_url()), self.req._(u'subscribe'),
+            self.req.external_resource('RSS_LOGO_16'), self.req._('rss icon')))
+
+    def render_entity_relations(self, entity):
+        super(BlogPrimaryView, self).render_entity_relations(entity)
+        rset = entity.related('entry_of', 'object')
+        strio = UStringIO()
+        self.pagination(self.req, rset, strio.write, page_size=10)
+        self.wview('adaptedlist', rset, 'null')
+        self.w(strio.getvalue())
+
+    def render_entity_title(self, entity):
+        self.w(u'<h1>%s</h1>' % xml_escape(entity.dc_title()))
+
+class BlogEntryPrimaryView(primary.PrimaryView):
+    __select__ = implements('BlogEntry')
+    show_attr_label = False
+
+    def render_entity_relations(self, entity):
+        rset = entity.related('entry_of', 'subject')
+        if rset:
+            self.w(self.req._('blogged in '))
+            self.wview('csv', rset, 'null')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/secondary.py	Tue Nov 03 21:29:29 2009 -0800
@@ -0,0 +1,197 @@
+"""Secondary views for blogs
+
+:organization: Logilab
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from calendar import monthrange
+from datetime import datetime
+
+from logilab.mtconverter import xml_escape
+
+from cubicweb.schema import display_name
+from cubicweb.view import EntityView, StartupView
+from cubicweb.selectors import paginated_rset, sorted_rset, implements
+from cubicweb.web.htmlwidgets import BoxLink, BoxWidget
+from cubicweb.web.views import baseviews, boxes, calendar, navigation
+
+class BlogEntryArchiveView(StartupView):
+    """control the view of a blog archive"""
+    id = 'blog_archive'
+    countrql = 'Any COUNT(B) WHERE B is BlogEntry, B creation_date >=  %(firstday)s, B creation_date <= %(lastday)s'
+
+    def represent(self, items, year, month):
+        """represent a single month entry"""
+        firstday = datetime(year, month, 1)
+        lastday = datetime(year, month, monthrange(year, month)[1])
+        rql = ('Any B, BD ORDERBY BD DESC '
+               'WHERE B is BlogEntry, B creation_date BD, '
+               'B creation_date >=  "%s", B creation_date <= "%s"' %
+                (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d')))
+        args = {'firstday':firstday, 'lastday':lastday}
+        nmb_entries = self.req.execute(self.countrql, args)[0][0]
+        label = u'%s %s [%s]' % (self.req._(calendar.MONTHNAMES[month-1]), year,
+                                 nmb_entries)
+        url = xml_escape(self.build_url('view', rql=rql))
+        link = u'<a href="%s" title="">%s</a>' % (url, label)
+        items.append( u'<li class="">%s</li>\n' % link )
+
+    def call(self, maxentries=None, **kwargs):
+        """display a list of entities by calling their <item_vid> view
+        """
+        rset = self.req.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD')
+
+        blogmonths = []
+        items = []
+        for (blogdate,) in rset:
+            year, month = blogdate.year, blogdate.month
+            if (year, month) not in blogmonths:
+                blogmonths.append( (year, month) )
+        if maxentries is None:
+            displayed_months = blogmonths
+            needmore = False
+        else:
+            needmore = len(blogmonths) > maxentries
+            displayed_months = blogmonths[:maxentries]
+        for year, month in displayed_months:
+            self.represent(items, year, month)
+        if needmore:
+            url = self.build_url('view', vid='blog_archive')
+            link = u'<a href="%s" title="">[see more archives]</a>' % url
+            items.append( u'<li class="">%s</li>\n' % link )
+        self.w(u'<div class="boxFrame">')
+        if items:
+            self.w(u'<div class="boxContent">\n')
+            self.w(u'<ul class="boxListing">')
+            self.w(''.join(items))
+            self.w(u'</ul>\n</div>\n')
+        self.w(u'</div>')
+
+
+class BlogEntryArchiveBox(boxes.BoxTemplate):
+    """blog side box displaying a Blog Archive"""
+    id = 'blog_archives_box'
+    title = _('boxes_blog_archives_box')
+    order = 35
+
+    def call(self, **kwargs):
+        """display blogs archive"""
+        # XXX turn into a selector
+        count_blogentry = self.req.execute('Any COUNT(B) WHERE B is BlogEntry')
+        if count_blogentry[0][0] > 0:
+            box = BoxWidget(self.req._(self.title), id=self.id, islist=False)
+            box.append(boxes.BoxHtml(self.view('blog_archive', None, maxentries=12)))
+            box.render(self.w)
+
+
+class BlogEntryListBox(boxes.BoxTemplate):
+    """display a box with latest blogs and rss"""
+    id = 'blog_latest_box'
+    title = _('blog_latest_box')
+    visible = True # enabled by default
+    order = 34
+
+    def call(self, view=None, **kwargs):
+        # XXX turn into a selector
+        rset = self.req.execute('Any X,T,CD ORDERBY CD DESC LIMIT 5 '
+                                'WHERE X is BlogEntry, X title T, '
+                                'X creation_date CD')
+        if not rset:
+            return
+        box = BoxWidget(self.req._(self.title), self.id, islist=True)
+        # TODO - get the date between brakets after link
+        # empty string for title argument to deactivate auto-title
+        for i in xrange(rset.rowcount):
+            entity = rset.get_entity(i, 0)
+            box.append(BoxLink(entity.absolute_url(), xml_escape(entity.dc_title())))
+        rqlst = rset.syntax_tree()
+        rqlst.set_limit(None)
+        rql = rqlst.as_string(kwargs=rset.args)
+        url = self.build_url('view', rql=rql, page_size=10)
+        box.append(BoxLink(url,  u'[%s]' % self.req._(u'see more')))
+        rss_icon = self.req.external_resource('RSS_LOGO_16')
+        # FIXME - could use rss_url defined as a property if available
+        rss_label = u'%s <img src="%s" alt="%s"/>' % (
+            self.req._(u'subscribe'), rss_icon, self.req._('rss icon'))
+        rss_url = self.build_url('view', vid='rss', rql=rql)
+        box.append(BoxLink(rss_url, rss_label))
+        box.render(self.w)
+
+
+## list views ##################################################################
+
+class BlogEntryAdaptedListView(baseviews.AdaptedListView):
+    __select__ = baseviews.AdaptedListView.__select__ & implements('BlogEntry')
+
+    def call(self, **kwargs):
+        self.req.add_css('cubes.blog.css')
+        super(BlogEntryAdaptedListView, self).call(**kwargs)
+
+class BlogEntryAdaptedListItemView(baseviews.AdaptedListItemView):
+    __select__ = baseviews.AdaptedListView.__select__ & implements('BlogEntry')
+    redirect_vid = 'blog'
+
+
+class BlogEntryBlogView(EntityView):
+    id = 'blog'
+    __select__ = implements('BlogEntry')
+
+    def cell_call(self, row, col):
+        entity = self.entity(row, col)
+        w = self.w
+        _ = self.req._
+        w(u'<div class="post">')
+        w(u'<h1>%s</h1>' % entity.view('incontext'))
+        w(u'%s ' % entity.postinfo_description())
+        creator = entity.creator
+        if creator:
+            vtitle = _('blog entries created by %s') % creator.name()
+            rql = 'Any X ORDERBY D DESC WHERE X is BlogEntry, X created_by Y, '\
+                  'Y eid %s, X creation_date D' % creator.eid
+            url = self.build_url('view', rql=rql, vtitle=vtitle, page_size=10)
+            w(u'%s <a title="%s" href="%s">%s</a>' % (
+                _('by'), xml_escape(vtitle), xml_escape(url), creator.name()))
+        w(u'<div class="entry">')
+        body = entity.printable_value('content')
+        w(body)
+        w(u'</div>')
+        w(u'<div class="postmetadata">%s</div>' % entity.view('post-reldata'))
+        w(u'</div>')
+
+
+class BlogEntryPostMetaData(EntityView):
+    id = 'post-reldata'
+    __select__ = implements('BlogEntry')
+
+    def cell_call(self, row, col):
+        entity = self.entity(row, col)
+        _ = lambda ertype, form='': display_name(self.req, ertype, form)
+        reldata = []
+        w = reldata.append
+        if 'comments' in self.schema and 'BlogEntry' in self.schema.rschema('comments').objects():
+            count = self.req.execute('Any COUNT(C) WHERE C comments B, B eid %(x)s',
+                                     {'x': entity.eid}, 'x')[0][0]
+            if count:
+                url = xml_escape(entity.absolute_url())
+                w(u'<a href="%s">%s %s</a>' % (url, count, _('Comment', 'plural')))
+            else:
+                w(u'%s %s' % (count, _('Comment')))
+        if 'tags' in self.schema and 'BlogEntry' in self.schema.rschema('tags').objects():
+            tag_rset = entity.related('tags', 'object')
+            if tag_rset:
+                w(u'%s %s' % (_('tags', 'object'), self.view('csv', tag_rset)))
+        rset = entity.related('entry_of', 'subject')
+        if rset:
+            w(u'%s %s' % (self.req._('blogged in '),
+                          self.view('csv', rset, 'null')))
+        self.w(u' | '.join(reldata))
+
+
+class BlogNavigation(navigation.PageNavigation):
+    __select__ = paginated_rset() & sorted_rset() & implements('BlogEntry')
+
+    def index_display(self, start, stop):
+        return u'%s' % (int(start / self.page_size)+1)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/urlpublishing.py	Tue Nov 03 21:29:29 2009 -0800
@@ -0,0 +1,34 @@
+from calendar import monthrange
+from datetime import datetime
+
+from cubicweb.web.views.urlrewrite import SimpleReqRewriter, rgx
+
+class BlogReqRewriter(SimpleReqRewriter):
+    rules = [
+        (rgx('/blogentry/([a-z_]+)'),
+         dict(rql='Any X ORDERBY CD DESC WHERE X is BlogEntry, X creation_date CD, X created_by U, U login "%(user)s"' % {'user': r'\1'},
+              user = r'\1')),
+        (rgx('/blogentry/([a-z_]+)\.rss'),
+         dict(rql='Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry, X creation_date CD, X created_by U, U login "%(user)s"' % {'user': r'\1'}, vid='rss')),
+        (rgx('/blogentries/([0-9]{4})'),
+         dict(rql='Any B ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD, '
+                  'B creation_date >= "%(param)s-01-01", '
+                  'B creation_date <= "%(param)s-12-31"' % {'param': r'\1'}, 
+              )),
+        (rgx('/blogentries/([0-9]{4})/([0-9]{2})'),
+         dict(rql='Any B, BD ORDERBY BD DESC '
+                  'WHERE B is BlogEntry, B creation_date BD, '
+                  'B creation_date >=  "%(year)s/%(month)s/01", B creation_date <= "%(year)s/%(month)s/30"' % {'year': r'\1', 'month': r'\2'},
+              )),
+        (rgx('/blog/([0-9]+)/blogentries/([0-9]{4})'),
+         dict(rql='Any B ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD, '
+                  'B creation_date >= "%(param)s-01-01", '
+                  'B creation_date <= "%(param)s-12-31", B entry_of BL, BL eid %(eid)s' % {'eid': r'\1', 'param': r'\2'}, 
+              )),
+        (rgx('/blog/([0-9]+)/blogentries/([0-9]{4})/([0-9]{2})'),
+         dict(rql='Any B, BD ORDERBY BD DESC '
+                  'WHERE B is BlogEntry, B creation_date BD, B entry_of BL, BL eid %(eid)s, '
+                  'B creation_date >=  "%(year)s/%(month)s/01", B creation_date <= "%(year)s/%(month)s/30"' % {'eid': r'\1', 'year': r'\2', 'month': r'\3'},
+              )),
+
+        ]