Compare commits
3 Commits
master
...
wip/bdauve
Author | SHA1 | Date |
---|---|---|
Benjamin Dauvergne | cb8b7cd2f4 | |
Benjamin Dauvergne | ac855ee9bb | |
Benjamin Dauvergne | 3245869817 |
8
README
8
README
|
@ -108,7 +108,9 @@ The config dictonnary can contain the following keys:
|
|||
content of the dictionnary is described later,
|
||||
- `template`, the template in which to render the data sources, it
|
||||
will receive a variable named `data_sources` in its context
|
||||
containing property named after the `slug` field of each source.
|
||||
containing property named after the `slug` field of each source,
|
||||
- `accepted_http_status`, a list of integers giving the accepted HTTP status,
|
||||
default is `[200]`.
|
||||
|
||||
A source definition is a dictionnary containing the following keys:
|
||||
- `slug`, the field name to hold this source parsed value in the
|
||||
|
@ -164,7 +166,9 @@ A source definition is a dictionnary containing the following keys:
|
|||
present,
|
||||
- `user_context`, whether the user must be part of the cache key. For retro
|
||||
compatibility If authentication mechanism is OAuth2, it defaults to True
|
||||
otherwise to False.
|
||||
otherwise to False,
|
||||
- `accepted_http_status`, a list of integers giving the accepted HTTP status,
|
||||
default is taken from the renderer level.
|
||||
|
||||
Exemple with the JSON parser
|
||||
----------------------------
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from cms.plugin_pool import plugin_pool
|
||||
from cms.plugin_base import CMSPluginBase
|
||||
|
||||
from . import models
|
||||
from . import models, utils
|
||||
|
||||
class BlurpPlugin(CMSPluginBase):
|
||||
name = _('Blurp Plugin')
|
||||
|
@ -12,26 +15,18 @@ class BlurpPlugin(CMSPluginBase):
|
|||
render_template = ''
|
||||
|
||||
def render(self, context, instance, placeholder):
|
||||
renderer = instance.get_renderer()
|
||||
request = context.get('request')
|
||||
ajax = context.get('ajaxy', True) and renderer.config.get('ajax', False)
|
||||
if not ajax:
|
||||
self.render_template = renderer.render_template()
|
||||
return renderer.render(context)
|
||||
else:
|
||||
request = context.get('request')
|
||||
context['plugin_id'] = instance.id
|
||||
context['ajax_refresh'] = renderer.config.get('ajax_refresh', 0)
|
||||
if request.GET:
|
||||
context['plugin_args'] = '?{0}'.format(request.GET.urlencode())
|
||||
# hack alert !!
|
||||
self.render_template = 'cmsplugin_blurp/ajax.html'
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
slug = instance.name
|
||||
template, context = utils.render_blurp(context, slug)
|
||||
self.render_template = template
|
||||
return context
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
except Exception, e:
|
||||
logger.exception('error while rendering blurp %s', slug)
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
msg = 'error while rendering blurp %s: %s' % (slug, e)
|
||||
self.render_template = 'cmsplugin_blurp/error.html'
|
||||
return {'content': msg}
|
||||
|
||||
|
||||
plugin_pool.register_plugin(BlurpPlugin)
|
||||
|
|
|
@ -40,3 +40,6 @@ class BaseRenderer(object):
|
|||
def render_template(self):
|
||||
'''Return a template path or a Template object'''
|
||||
pass
|
||||
|
||||
def use_ajax(self, context):
|
||||
return self.config.get('ajax', False)
|
||||
|
|
|
@ -37,6 +37,7 @@ class Renderer(template.TemplateRenderer):
|
|||
'timeout': 10, # optional default is 1, it cannot be less than 1
|
||||
'refresh': 3600, # optional, default is taken from the renderer level
|
||||
'limit': 0, # optional, default is taken from the renderer level
|
||||
'accepted_http_status': [200,400], # optional, default it taken from the renderer level
|
||||
},
|
||||
]
|
||||
'template_name': 'data_from_xyz.html'
|
||||
|
@ -51,9 +52,11 @@ class Renderer(template.TemplateRenderer):
|
|||
# not limited if it is 0
|
||||
# you can also override it in each source
|
||||
'limit': 0, # optional default is 0
|
||||
'accepted_http_status': [200,400], # optional, default is [200]
|
||||
}
|
||||
|
||||
'''
|
||||
__sources = None
|
||||
|
||||
@classmethod
|
||||
def check_config(cls, config):
|
||||
|
@ -78,12 +81,17 @@ class Renderer(template.TemplateRenderer):
|
|||
yield 'missing signature_key string'
|
||||
|
||||
def get_sources(self, context):
|
||||
for source in self.config['sources']:
|
||||
slug = '{0}.{1}'.format(self.slug, source['slug'])
|
||||
data = Data(slug, self.config, source, context)
|
||||
yield source['slug'], data
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
yield 'blurp_debug__', '\n'.join(self.debug_content(context))
|
||||
if self.__sources is None:
|
||||
sources = []
|
||||
for source in self.config['sources']:
|
||||
slug = '{0}.{1}'.format(self.slug, source['slug'])
|
||||
data = Data(slug, self.config, source, context)
|
||||
sources.append((source['slug'], data))
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
sources.append(('blurp_debug__',
|
||||
'\n'.join(self.debug_content(context))))
|
||||
self.__sources = sources
|
||||
return self.__sources
|
||||
|
||||
def debug_content(self, context):
|
||||
try:
|
||||
|
@ -100,6 +108,15 @@ class Renderer(template.TemplateRenderer):
|
|||
except Exception, e:
|
||||
yield u'slug {0!r}: pformat failed {1!r}'.format(slug, e)
|
||||
|
||||
def use_ajax(self, context):
|
||||
'''Only use ajax if some content is not cached'''
|
||||
if super(Renderer, self).use_ajax(context):
|
||||
for source in self.get_sources():
|
||||
if not source.content_is_cached():
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def render(self, context):
|
||||
for slug, source in self.get_sources(context):
|
||||
context[slug] = source
|
||||
|
@ -141,6 +158,8 @@ class Data(object):
|
|||
self.signature_key = source.get('signature_key')
|
||||
self.parser_type = source.get('parser_type', 'raw')
|
||||
self.content_type = source.get('content_type', self.MAPPING[self.parser_type])
|
||||
self.accepted_http_status = source.get('accepted_http_status',
|
||||
config.get('accepted_http_status', [200]))
|
||||
self.user_context = source.get('user_context',
|
||||
config.get('user_context', self.auth_mech == 'oauth2'))
|
||||
pre_hash = 'datasource-{self.slug}-{self.url}-{self.limit}-' \
|
||||
|
@ -195,7 +214,8 @@ class Data(object):
|
|||
allow_redirects=self.redirects,
|
||||
timeout=self.timeout,
|
||||
stream=True)
|
||||
request.raise_for_status()
|
||||
if request.status_code not in self.accepted_http_status:
|
||||
request.raise_for_status()
|
||||
return request.raw, None
|
||||
except HTTPError:
|
||||
error = 'HTTP Error %s when loading URL %s for renderer %r' % (
|
||||
|
@ -271,6 +291,23 @@ class Data(object):
|
|||
UPDATE_THREADS = {}
|
||||
CONDITIONS = {}
|
||||
|
||||
def content_is_cached(self, ignore_stale_content=True):
|
||||
'''Test if some content is in cache'''
|
||||
if self.__content is self.__CACHE_SENTINEL:
|
||||
content, until = cache.get(self.key, (self.__CACHE_SENTINEL, None))
|
||||
if not ignore_stale_content:
|
||||
self.__content = content
|
||||
if until is not None and ignore_stale_content and until < self.now:
|
||||
return False
|
||||
if self.refresh <= 0:
|
||||
return False
|
||||
if self.request and 'updatecache' in self.request.GET:
|
||||
return False
|
||||
self.__content = content
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_content(self):
|
||||
if self.__content is not self.__CACHE_SENTINEL:
|
||||
return self.__content
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
if ($ == undefined) {
|
||||
alert('jQuery is missing');
|
||||
} else {
|
||||
var $container = $("#block-plugin-ajax-{{ plugin_id }}");
|
||||
var $container = $("#block-plugin-ajax-{{ slug }}");
|
||||
var ajax_refresh = {{ ajax_refresh }};
|
||||
var exponential_refresh = ajax_refresh;
|
||||
var reload = function () {
|
||||
$container.removeClass('block-plugin-ajax-failed');
|
||||
$container.addClass('block-plugin-ajax-loading');
|
||||
$.getJSON('{% url 'ajax_render' plugin_id=plugin_id %}{{ plugin_args|safe }}', function (result) {
|
||||
$.getJSON('{% url 'ajax_render' slug=slug %}{{ plugin_args|safe }}', function (result) {
|
||||
$container.html(result.content);
|
||||
$container.removeClass('block-plugin-ajax-loading');
|
||||
if (ajax_refresh > 0) {
|
||||
|
@ -38,7 +38,7 @@
|
|||
</script>
|
||||
{% endaddtoblock %}
|
||||
|
||||
<div id="block-plugin-ajax-{{ plugin_id }}" class='block-plugin-ajax block-plugin-ajax-loading'>
|
||||
<div id="block-plugin-ajax-{{ slug }}" class='block-plugin-ajax block-plugin-ajax-loading'>
|
||||
<div class="block-plugin-ajax-placeholder">{% trans "loading..." %}</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -32,25 +32,22 @@ class RenderBlurp(Tag):
|
|||
)
|
||||
|
||||
|
||||
def render_tag(self, context, name):
|
||||
renderer = utils.resolve_renderer(name)
|
||||
if not renderer:
|
||||
return ''
|
||||
template = renderer.render_template()
|
||||
context = renderer.render(context)
|
||||
def render_tag(self, context, slug):
|
||||
context.push()
|
||||
try:
|
||||
if not hasattr(template, 'render'):
|
||||
template = template.Template(template)
|
||||
return template.render(context)
|
||||
except Exception, e:
|
||||
logging.getLogger(__name__).exception('error while rendering %s',
|
||||
renderer)
|
||||
msg = ''
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
msg += 'error while rendering %s: %s' % (renderer, e)
|
||||
msg = '<pre>%s</pre>' % escape(msg)
|
||||
return msg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
template, context = utils.render_blurp(context, slug)
|
||||
return template.render(context)
|
||||
except Exception, e:
|
||||
logger.exception('error while rendering blurp %s', slug)
|
||||
msg = ''
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
msg += 'error while rendering blurp %s: %s' % (slug, e)
|
||||
msg = '<pre>%s</pre>' % escape(msg)
|
||||
return msg
|
||||
finally:
|
||||
context.pop()
|
||||
|
||||
@register.tag
|
||||
class BlurpNode(Tag):
|
||||
|
@ -60,9 +57,11 @@ class BlurpNode(Tag):
|
|||
Argument('name'),
|
||||
blocks=[('endblurp', 'nodelist')])
|
||||
|
||||
def render_tag(self, context, name, nodelist):
|
||||
def render_tag(self, context, slug, nodelist):
|
||||
context.push()
|
||||
utils.insert_blurp_in_context(name, context)
|
||||
output = self.nodelist.render(context)
|
||||
context.pop()
|
||||
return output
|
||||
try:
|
||||
utils.insert_blurp_in_context(slug, context)
|
||||
output = self.nodelist.render(context)
|
||||
return output
|
||||
finally:
|
||||
context.pop()
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.conf.urls import patterns, url
|
|||
from . import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^block-plugin-async/(?P<plugin_id>\d+)/$',
|
||||
url(r'^block-plugin-async/(?P<slug>\w+)/$',
|
||||
views.ajax_render,
|
||||
name='ajax_render')
|
||||
)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import logging
|
||||
|
||||
from django.utils.importlib import import_module
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.template.loader import get_template
|
||||
|
||||
from . import app_settings
|
||||
|
||||
|
@ -34,3 +37,26 @@ def insert_blurp_in_context(name, context):
|
|||
if not renderer:
|
||||
return ''
|
||||
return renderer.render(context)
|
||||
|
||||
def render_blurp(context, slug, ajax=True):
|
||||
logger = logging.getLogger(__name__)
|
||||
renderer = resolve_renderer(slug)
|
||||
if not renderer:
|
||||
logger.warning('renderer %s does not exist', slug)
|
||||
return None, None
|
||||
# Ajax rendering is canceled in the ajax view
|
||||
ajax = ajax and renderer.use_ajax(context)
|
||||
if ajax:
|
||||
request = context.get('request')
|
||||
context['slug'] = renderer.slug
|
||||
context['ajax_refresh'] = renderer.config.get('ajax_refresh', 0)
|
||||
if request.GET:
|
||||
context['plugin_args'] = '?{0}'.format(request.GET.urlencode())
|
||||
# hack alert !!
|
||||
template = get_template('cmsplugin_blurp/ajax.html', context)
|
||||
else:
|
||||
template = renderer.render_template()
|
||||
if not hasattr(template, 'render'):
|
||||
template = template.Template(template)
|
||||
context = renderer.render(context)
|
||||
return template, context
|
||||
|
|
|
@ -2,20 +2,27 @@ import json
|
|||
import logging
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.template import RequestContext, loader
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.utils.html import escape
|
||||
from django.conf import settings
|
||||
|
||||
from cms.models import CMSPlugin
|
||||
from . import utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def ajax_render(request, plugin_id):
|
||||
def ajax_render(request, slug):
|
||||
context = RequestContext(request)
|
||||
context['ajaxy'] = False
|
||||
plugin = get_object_or_404(CMSPlugin, pk=plugin_id)
|
||||
rendered = plugin.render_plugin(context)
|
||||
# use another template to render accumulated js and css declarations from sekizai
|
||||
content = loader.render_to_string('cmsplugin_blurp/sekizai_render.html',
|
||||
{'content': rendered}, context)
|
||||
return HttpResponse(json.dumps({'content': content}))
|
||||
template, context = utils.render_blurp(context, slug, ajax=False)
|
||||
result = {}
|
||||
try:
|
||||
template, context = utils.render_blurp(context, slug)
|
||||
result['content'] = template.render(context)
|
||||
except Exception, e:
|
||||
logger.exception('error while rendering blurp %s', slug)
|
||||
msg = ''
|
||||
result['error'] = msg
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
msg += 'error while rendering blurp %s: %s' % (slug, e)
|
||||
result['content'] = '<pre>%s</pre>' % escape(msg)
|
||||
return HttpResponse(json.dumps(result))
|
||||
|
||||
|
|
Reference in New Issue