--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_pagelet/pagelet.py Thu Feb 19 10:54:13 2015 +0100
@@ -0,0 +1,150 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard packages
+import venusian
+
+# import interfaces
+from pyams_pagelet.interfaces import IPagelet, IPageletRenderer, PageletCreatedEvent
+from pyams_template.interfaces import IContentTemplate, ILayoutTemplate
+from pyramid.interfaces import IRequest
+from pyramid_chameleon.interfaces import IChameleonTranslate
+
+# import packages
+from pyams_utils.adapter import adapter_config
+from pyramid.httpexceptions import HTTPUnauthorized
+from pyramid.response import Response
+from zope.component import queryUtility
+from zope.interface import implementer, Interface
+
+
+REDIRECT_STATUS_CODES = (301, 302, 303)
+
+
+@implementer(IPagelet)
+class Pagelet(object):
+ """Content provider with layout support"""
+
+ template = None
+ layout = None
+ permission = None
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+ if self.permission and not request.has_permission(self.permission):
+ raise HTTPUnauthorized('You are not authorized to access the page called `%s`.' %
+ request.view_name)
+ request.registry.notify(PageletCreatedEvent(self))
+
+ def update(self):
+ self.request.annotations['view'] = self
+
+ def render(self):
+ request = self.request
+ cdict = {'context': self.context,
+ 'request': request,
+ 'view': self,
+ 'translate': queryUtility(IChameleonTranslate)}
+ if self.template is None:
+ registry = request.registry
+ template = registry.queryMultiAdapter((self, request, self.context),
+ IContentTemplate)
+ if template is None:
+ template = registry.getMultiAdapter((self, request), IContentTemplate)
+ return template(**cdict)
+ return self.template(**cdict)
+
+ def __call__(self, **kwargs):
+ """Call update and return layout template"""
+ self.update()
+ if self.request.response.status_code in REDIRECT_STATUS_CODES:
+ return ''
+
+ request = self.request
+ cdict = {'context': self.context,
+ 'request': request,
+ 'view': self,
+ 'translate': queryUtility(IChameleonTranslate)}
+ cdict.update(kwargs)
+ if self.layout is None:
+ registry = request.registry
+ layout = registry.queryMultiAdapter((self, request, self.context),
+ ILayoutTemplate)
+ if layout is None:
+ layout = registry.getMultiAdapter((self, request), ILayoutTemplate)
+ return Response(layout(**cdict))
+ return Response(self.layout(**cdict))
+
+
+@adapter_config(name='pagelet', context=(Interface, IRequest, IPagelet), provides=IPageletRenderer)
+class PageletRenderer(object):
+ """Pagelet renderer"""
+
+ def __init__(self, context, request, pagelet):
+ self.__updated = False
+ self.__parent__ = pagelet
+ self.context = context
+ self.request = request
+
+ def update(self):
+ pass
+
+ def render(self):
+ return self.__parent__.render()
+
+
+class pagelet_config(object):
+ """Function or class decorator used to declare a pagelet"""
+
+ venusian = venusian # for testing injection
+
+ def __init__(self, **settings):
+ if 'for_' in settings:
+ if settings.get('context') is None:
+ settings['context'] = settings.pop('for_')
+ if 'layer' in settings:
+ settings['request_type'] = settings.pop('layer')
+ self.__dict__.update(settings)
+
+ def __call__(self, wrapped):
+ settings = self.__dict__.copy()
+ depth = settings.pop('_depth', 0)
+
+ def callback(context, name, ob):
+ cdict = {}
+ cdict['__name__'] = settings.get('name')
+ cdict['permission'] = settings.get('permission')
+ new_class = type(ob.__name__, (ob, Pagelet), cdict)
+
+ config = context.config.with_package(info.module)
+ config.registry.registerAdapter(new_class,
+ (settings.get('context', Interface),
+ settings.get('request_type', IRequest)),
+ IPagelet, settings.get('name'))
+ config.add_view(view=new_class, **settings)
+
+ info = self.venusian.attach(wrapped, callback, category='pyams_pagelet',
+ depth=depth + 1)
+
+ if info.scope == 'class':
+ # if the decorator was attached to a method in a class, or
+ # otherwise executed at class scope, we need to set an
+ # 'attr' into the settings if one isn't already in there
+ if settings.get('attr') is None:
+ settings['attr'] = wrapped.__name__
+
+ settings['_info'] = info.codeinfo # fbo "action_method"
+ return wrapped