[ext/rest] add directive bookmark to rest (closes #2545595)
authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
Thu, 04 Apr 2013 17:45:09 +0200
changeset 8852 59a29405688c
parent 8851 0020aa12af07
child 8867 6ad000b91347
[ext/rest] add directive bookmark to rest (closes #2545595)
doc/3.17.rst
doc/book/en/tutorials/index.rst
doc/book/en/tutorials/textreports/index.rst
ext/rest.py
ext/test/unittest_rest.py
--- a/doc/3.17.rst	Wed Apr 03 12:17:24 2013 +0200
+++ b/doc/3.17.rst	Thu Apr 04 17:45:09 2013 +0200
@@ -10,6 +10,9 @@
 * Add CubicWebRequestBase.content with the content of the HTTP request (see #2742453)
   (see `#2742453 <http://www.cubicweb.org/2742453>`_)
 
+* Add directive bookmark to ReST rendering
+  (see `#2545595 <http://www.cubicweb.org/ticket/2545595>`_)
+
 
 API changes
 -----------
--- a/doc/book/en/tutorials/index.rst	Wed Apr 03 12:17:24 2013 +0200
+++ b/doc/book/en/tutorials/index.rst	Thu Apr 04 17:45:09 2013 +0200
@@ -18,3 +18,4 @@
    base/index
    advanced/index
    tools/windmill.rst
+   textreports/index
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/textreports/index.rst	Thu Apr 04 17:45:09 2013 +0200
@@ -0,0 +1,13 @@
+.. -*- coding: utf-8 -*-
+
+Writing text reports with RestructuredText
+==========================================
+
+|cubicweb| offers several text formats for the RichString type used in schemas,
+including restructuredtext.
+
+Three additional restructuredtext roles are defined by |cubicweb|:
+
+.. autodocfunction:: cubicweb.ext.rest.eid_reference_role
+.. autodocfunction:: cubicweb.ext.rest.rql_role
+.. autodocfunction:: cubicweb.ext.rest.bookmark_role
--- a/ext/rest.py	Wed Apr 03 12:17:24 2013 +0200
+++ b/ext/rest.py	Thu Apr 04 17:45:09 2013 +0200
@@ -36,6 +36,7 @@
 from itertools import chain
 from logging import getLogger
 from os.path import join
+from urlparse import urlsplit
 
 from docutils import statemachine, nodes, utils, io
 from docutils.core import Publisher
@@ -128,6 +129,63 @@
     set_classes(options)
     return [nodes.raw('', content, format='html')], []
 
+def bookmark_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
+    """:bookmark:`<bookmark-eid>` or :bookmark:`<eid>:<vid>`
+
+    Example: :bookmark:`1234:table`
+
+    Replace the directive with the output of applying the view to the resultset
+    returned by the query stored in the bookmark. By default, the view is the one
+    stored in the bookmark, but it can be overridden by the directive as in the
+    example above.
+
+    "X eid %(userid)s" can be used in the RQL query stored in the Bookmark, for
+    this query will be executed with the argument {'userid': _cw.user.eid}.
+    """
+    _cw = inliner.document.settings.context._cw
+    text = text.strip()
+    try:
+        if ':' in text:
+            eid, vid = text.rsplit(u':', 1)
+            eid = int(eid)
+        else:
+            eid, vid = int(text), None
+    except ValueError:
+        msg = inliner.reporter.error(
+            'EID number must be a positive number; "%s" is invalid.'
+            % text, line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    try:
+        bookmark = _cw.entity_from_eid(eid)
+    except UnknownEid:
+        msg = inliner.reporter.error('Unknown EID %s.' % text, line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    try:
+        params = dict(_cw.url_parse_qsl(urlsplit(bookmark.path).query))
+        rql = params['rql']
+        if vid is None:
+            vid = params.get('vid')
+    except (ValueError, KeyError), exc:
+        msg = inliner.reporter.error('Could not parse bookmark path %s [%s].'
+                                     % (bookmark.path, exc), line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    try:
+        rset = _cw.execute(rql, {'userid': _cw.user.eid})
+        if rset:
+            if vid is None:
+                vid = vid_from_rset(_cw, rset, _cw.vreg.schema)
+        else:
+            vid = 'noresult'
+        view = _cw.vreg['views'].select(vid, _cw, rset=rset)
+        content = view.render()
+    except Exception, exc:
+        content = 'An error occured while interpreting directive bookmark: %r' % exc
+    set_classes(options)
+    return [nodes.raw('', content, format='html')], []
+
 def winclude_directive(name, arguments, options, content, lineno,
                        content_offset, block_text, state, state_machine):
     """Include a reST file as part of the content of this reST file.
@@ -323,6 +381,7 @@
     _INITIALIZED = True
     register_canonical_role('eid', eid_reference_role)
     register_canonical_role('rql', rql_role)
+    register_canonical_role('bookmark', bookmark_role)
     directives.register_directive('winclude', winclude_directive)
     if pygments_directive is not None:
         directives.register_directive('sourcecode', pygments_directive)
--- a/ext/test/unittest_rest.py	Wed Apr 03 12:17:24 2013 +0200
+++ b/ext/test/unittest_rest.py	Thu Apr 04 17:45:09 2013 +0200
@@ -75,5 +75,12 @@
         out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`')
         self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section"><a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a></div><div class="section"><a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a></div></p>\n')
 
+    def test_bookmark_role(self):
+        context = self.context()
+        rset = self.execute('INSERT Bookmark X: X title "hello", X path "/view?rql=Any X WHERE X is CWUser"')
+        eid = rset[0][0]
+        out = rest_publish(context, ':bookmark:`%s`' % eid)
+        self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section"><a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a></div><div class="section"><a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a></div></p>\n')
+
 if __name__ == '__main__':
     unittest_main()