mitar committed c0f4629

Added macro which renders added text plugins.

Comments (0)

Files changed (2)


 from django import template
 from django.template import defaulttags
+from cms.models import pluginmodel as plugin_models
 class DjangoTagMacroBase(macros.WikiMacroBase):
     def expand_macro(self, formatter, name, content):
         tag = getattr(defaulttags, self.django_tag_name)
         node = tag(template.Parser(''), template.Token(template.TOKEN_BLOCK, "%s %s" % (self.django_tag_name, content)))
-        return node.render(template.Context({}))
+        return node.render(formatter.req.django_context)
     def get_macros(self):
         yield self.django_tag_name
-    # TODO: Retain the same Django context through whole rendering of wiki content? So that "as" could work? But what then, it should be possible to output it somehow, too.
     django_tag_name = 'url'
 class NowMacro(DjangoTagMacroBase):
     django_tag_name = 'now'
+class CMSPluginMacro(macros.WikiMacroBase):
+    """Macro which renders Django CMS plugin.
+    It takes only one argument, an object ID of a Django CMS plugin which is attached to the markup plugin using this macro. Attaching
+    the plugin and inserting the proper ID is done by the Django CMS itself so using this macro by its own has little practical use.
+    Examples:
+    {{{
+        [[CMSPlugin(42)]]
+    }}}
+    """
+    def expand_macro(self, formatter, name, content):
+        request = formatter.req.django_request
+        context = formatter.req.django_context
+        placeholder = formatter.req.django_placeholder
+        try:
+            plugin = plugin_models.CMSPlugin.objects.get(pk=content.strip())
+            plugin._render_meta.text_enabled = True
+            return plugin.render_plugin(context, placeholder)
+        except Exception as e:
+            # TODO: Log
+            if (request.user.is_authenticated() and request.user.is_staff) or 'preview' in request.GET:
+                raise e
+            else:
+                return u''


 from trac.util import datefmt, translation as trac_translation
 from trac.web import main
+from django import template
 from django.contrib.sites import models as sites_models
 from django.core import urlresolvers
 from django.db.models import Q
 components = [
+    'cmsplugin_markup_tracwiki.tracwiki.DjangoComponent',
-    '',
-    'cmsplugin_markup_tracwiki.tracwiki.DjangoResource',
+    'cmsplugin_markup_tracwiki.macros.CMSPluginMacro',
             self.abs_href = web.href.Href('http://' + site.domain + (':' + server_port if server_port != '80' else '') + self.href())
 class DjangoRequest(web.Request):
-    def __init__(self, request):
+    def __init__(self, request, context, placeholder):
         super(DjangoRequest, self).__init__(request.META, self._start_response)
         self.django_request = request
+        self.django_context = context
+        self.django_placeholder = placeholder
         self.perm = main.FakePerm()
         self.session = main.FakeSession()
         """We override _make_lhref_link to make 'cms' namespace default."""
         return super(DjangoFormatter, self)._make_lhref_link(match, fullmatch, rel, ns or 'cms', target, label)
-class DjangoResource(Component):
+class DjangoResource(resource.Resource):
+    __slots__ = ('django_request')
+class DjangoComponent(Component):
     implements(resource.IResourceManager, wiki.IWikiSyntaxProvider)
     def _format_link(self, formatter, ns, target, label, fullmatch=None):
         link, params, fragment = formatter.split_link(target)
-        page = resource.Resource(ns, link)
+        page = DjangoResource(ns, link)
+        page.django_request = _get_django_request(req=formatter.req)
             href = resource.get_resource_url(self.env, page, formatter.href)
             title = resource.get_resource_name(self.env, page)
             return href(**kwargs)
         elif res.realm == 'filer':
-                link = self._get_file(
+                link = self._get_file(res).url
             except filer_models.File.DoesNotExist as e:
                 raise resource.ResourceNotFound(e)
         elif res.realm == 'cms':
-                request = _get_django_request()
+                request = _get_django_request(res=res)
                 lang = cms_utils.get_language_from_request(request)
-                link = self._get_page(
+                link = self._get_page(res).get_absolute_url(language=lang)
             except cms_models.Page.DoesNotExist:
                     # Test again as request.current_page could be None
         return href(*args, **kwargs)
-    def get_resource_description(self, res, format='default', context=None, **kwargs):
+    def get_resource_description(self, res, format='default', ctx=None, **kwargs):
         if is None or not res.realm:
             return ''
         elif res.realm == 'filer':
-            return self._get_file(, context).label
+            return self._get_file(res, ctx).label
         elif res.realm == 'cms':
-                request = _get_django_request()
+                request = _get_django_request(res=res, ctx=ctx)
                 lang = cms_utils.get_language_from_request(request)
-                return self._get_page(, context).get_title(language=lang)
+                return self._get_page(res, ctx).get_title(language=lang)
             except cms_models.Page.DoesNotExist:
                 return ''
             return False
         elif res.realm == 'filer':
-                self._get_file(
+                self._get_file(res)
                 return True
             except filer_models.File.DoesNotExist:
                 return False
         elif res.realm == 'cms':
-                self._get_page(
+                self._get_page(res)
                 return True
             except cms_models.Page.DoesNotExist:
             raise RuntimeError("This should be impossible")
-    def _get_page(self, page_id, context=None):
-        if context is not None:
-            request = context.req.django_request
-        else:
-            request = _get_django_request()
+    def _get_page(self, res, ctx=None):
+        page_id =
+        request = _get_django_request(res=res, ctx=ctx)
         if not page_id:
             # is required for this
             if request.current_page:
             return moderator.get_page_queryset(request).get(reverse_id=page_id)
-    def _get_file(self, file_id, context=None):
+    def _get_file(self, res, ctx=None):
+        file_id =
         if not file_id:
             raise filer_models.File.DoesNotExist()
-        if context is not None:
-            request = context.req.django_request
-        else:
-            request = _get_django_request()
+        request = _get_django_request(res=res, ctx=ctx)
         f = filer_models.File.objects.get(Q(original_filename=file_id) | Q(name=file_id) | Q(sha1=file_id) | Q(file=file_id))
         if f.is_public or f.has_read_permission(request):
             return f
         yield ('cms', self._format_link)
         yield ('filer', self._format_link)
-# TODO: Make a macro similar to [[Image]] but which uses filer, but should also support thumbnail tag (or do another one for that?)
 # TODO: Relative links [..] should traverse Django CMS hierarchy
 # TODO: Make Trac and Django CMS caching interoperate (how does dynamic macros currently behave?)
 # TODO: Does request really have URL we want (for example in admin URL is not the URL of a resulting page)
 # TODO: Do we really need to use href() or should we just use Django URLs directly (as we configure href() with Django base URL anyway)
 # TODO: When using django-reversion, add an option to compare versions of plugin content and display it in the same way as Trac does
+# TODO: Is markup object really reused or is it created (and DjangoEnvironment with it) again and again for each page display?
 class Markup(markup_plugins.MarkupBase):
     name = 'Trac wiki'
     def __init__(self, *args, **kwargs):
         self.env = DjangoEnvironment()
-    def parse(self, value):
-        request = _get_django_request()
+    def parse(self, value, context=None, placeholder=None):
+        request = _get_django_request(context=context)
-        req = DjangoRequest(request)
-        res = resource.Resource('cms', 'pages-root') # TODO: Get ID from request (and version?)
+        if not context:
+            context = template.RequestContext(request, {})
+        req = DjangoRequest(request, context, placeholder)
+        res = DjangoResource('cms', 'pages-root') # TODO: Get ID from request (and version?)
         ctx = mimeview.Context.from_request(req, res)
         out = StringIO()
         DjangoFormatter(self.env, ctx).format(value, out)
     def plugin_regexp(self):
         return safestring.mark_safe(r"""function(plugin_id) { return new RegExp('\\[\\[CMSPlugin\\(\\s*' + plugin_id + '\\s*\\)\\]\\]', 'g'); }""")
-def _get_django_request():
+def _get_django_request(req=None, context=None, res=None, ctx=None):
+    if req and hasattr(req, 'django_request'):
+        return req.django_request
+    if context and 'request' in context:
+        return context['request']
+    if hasattr(res, 'django_request'):
+        return res.django_request
+    if ctx and ctx.req and hasattr(ctx.req, 'django_request'):
+        return ctx.req.django_request
     frame = inspect.currentframe()
         while frame.f_back:
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
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.