8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
|
13 """PyAMS_pagelet.pagelet module |
|
14 |
|
15 This module provides the core pagelet implementation, and a "pagelet_config" decorator which |
|
16 can be use to register pagelets instead of ZCML directives. |
|
17 """ |
|
18 |
|
19 import logging |
|
20 |
|
21 import venusian |
|
22 from pyramid.httpexceptions import HTTPUnauthorized |
|
23 from pyramid.interfaces import IRequest |
|
24 from pyramid.response import Response |
|
25 from pyramid_chameleon.interfaces import IChameleonTranslate |
|
26 from zope.component import queryUtility |
|
27 from zope.interface import Interface, implementer |
|
28 |
|
29 from pyams_pagelet.interfaces import IPagelet, IPageletRenderer, PageletCreatedEvent |
|
30 from pyams_template.interfaces import IContentTemplate, ILayoutTemplate |
|
31 from pyams_utils.adapter import adapter_config |
|
32 |
|
33 |
13 __docformat__ = 'restructuredtext' |
34 __docformat__ = 'restructuredtext' |
14 |
35 |
15 |
36 LOGGER = logging.getLogger('PyAMS (pagelet)') |
16 # import standard packages |
|
17 import logging |
|
18 logger = logging.getLogger('PyAMS (pagelet)') |
|
19 |
|
20 import venusian |
|
21 |
|
22 # import interfaces |
|
23 from pyams_pagelet.interfaces import IPagelet, IPageletRenderer, PageletCreatedEvent |
|
24 from pyams_template.interfaces import IContentTemplate, ILayoutTemplate |
|
25 from pyramid.interfaces import IRequest |
|
26 from pyramid_chameleon.interfaces import IChameleonTranslate |
|
27 |
|
28 # import packages |
|
29 from pyams_utils.adapter import adapter_config |
|
30 from pyramid.httpexceptions import HTTPUnauthorized |
|
31 from pyramid.response import Response |
|
32 from zope.component import queryUtility |
|
33 from zope.interface import implementer, Interface |
|
34 |
|
35 |
37 |
36 REDIRECT_STATUS_CODES = (301, 302, 303) |
38 REDIRECT_STATUS_CODES = (301, 302, 303) |
37 |
39 |
38 |
40 |
39 @implementer(IPagelet) |
41 @implementer(IPagelet) |
40 class Pagelet(object): |
42 class Pagelet: |
41 """Content provider with layout support""" |
43 """Content provider with layout support""" |
42 |
44 |
43 template = None |
45 template = None |
44 layout = None |
46 layout = None |
45 permission = None |
47 permission = None |
51 raise HTTPUnauthorized('You are not authorized to access the page called `%s`.' % |
53 raise HTTPUnauthorized('You are not authorized to access the page called `%s`.' % |
52 request.view_name) |
54 request.view_name) |
53 request.registry.notify(PageletCreatedEvent(self)) |
55 request.registry.notify(PageletCreatedEvent(self)) |
54 |
56 |
55 def update(self): |
57 def update(self): |
56 self.request.annotations['view'] = self |
58 """See `zope.contentprovider.interfaces.IContentProvider`""" |
|
59 annotations = getattr(self.request, 'annotations', None) |
|
60 if annotations is not None: |
|
61 annotations['view'] = self |
57 |
62 |
58 def render(self): |
63 def render(self): |
|
64 """See `zope.contentprovider.interfaces.IContentProvider`""" |
59 request = self.request |
65 request = self.request |
60 cdict = {'context': self.context, |
66 cdict = { |
61 'request': request, |
67 'context': self.context, |
62 'view': self, |
68 'request': request, |
63 'translate': queryUtility(IChameleonTranslate)} |
69 'view': self, |
|
70 'translate': queryUtility(IChameleonTranslate) |
|
71 } |
64 if self.template is None: |
72 if self.template is None: |
65 registry = request.registry |
73 registry = request.registry |
66 template = registry.queryMultiAdapter((self, request, self.context), |
74 template = registry.queryMultiAdapter((self, request, self.context), |
67 IContentTemplate) |
75 IContentTemplate) |
68 if template is None: |
76 if template is None: |
69 template = registry.getMultiAdapter((self, request), IContentTemplate) |
77 template = registry.getMultiAdapter((self, request), IContentTemplate) |
70 return template(**cdict) |
78 return template(**cdict) |
71 return self.template(**cdict) |
79 return self.template(**cdict) # pylint: disable=not-callable |
72 |
80 |
73 def __call__(self, **kwargs): |
81 def __call__(self, **kwargs): |
74 """Call update and return layout template""" |
82 """Call update and return layout template""" |
75 self.update() |
83 self.update() |
76 if self.request.response.status_code in REDIRECT_STATUS_CODES: |
84 if self.request.response.status_code in REDIRECT_STATUS_CODES: |
77 return '' |
85 return '' |
78 |
86 |
79 request = self.request |
87 request = self.request |
80 cdict = {'context': self.context, |
88 cdict = { |
81 'request': request, |
89 'context': self.context, |
82 'view': self, |
90 'request': request, |
83 'translate': queryUtility(IChameleonTranslate)} |
91 'view': self, |
|
92 'translate': queryUtility(IChameleonTranslate) |
|
93 } |
84 cdict.update(kwargs) |
94 cdict.update(kwargs) |
85 if self.layout is None: |
95 if self.layout is None: |
86 registry = request.registry |
96 registry = request.registry |
87 layout = registry.queryMultiAdapter((self, request, self.context), |
97 layout = registry.queryMultiAdapter((self, request, self.context), |
88 ILayoutTemplate) |
98 ILayoutTemplate) |
89 if layout is None: |
99 if layout is None: |
90 layout = registry.getMultiAdapter((self, request), ILayoutTemplate) |
100 layout = registry.getMultiAdapter((self, request), ILayoutTemplate) |
91 return Response(layout(**cdict)) |
101 return Response(layout(**cdict)) |
92 return Response(self.layout(**cdict)) |
102 return Response(self.layout(**cdict)) # pylint: disable=not-callable |
93 |
103 |
94 |
104 |
95 @adapter_config(name='pagelet', context=(Interface, IRequest, IPagelet), provides=IPageletRenderer) |
105 @adapter_config(name='pagelet', context=(Interface, IRequest, IPagelet), provides=IPageletRenderer) |
96 class PageletRenderer(object): |
106 class PageletRenderer: |
97 """Pagelet renderer""" |
107 """Pagelet renderer""" |
98 |
108 |
99 def __init__(self, context, request, pagelet): |
109 def __init__(self, context, request, pagelet): |
100 self.__updated = False |
110 self.__updated = False |
101 self.__parent__ = pagelet |
111 self.__parent__ = pagelet |
102 self.context = context |
112 self.context = context |
103 self.request = request |
113 self.request = request |
104 |
114 |
105 def update(self): |
115 def update(self): |
106 pass |
116 """See `zope.contentprovider.interfaces.IContentProvider`""" |
107 |
117 |
108 def render(self): |
118 def render(self): |
|
119 """See `zope.contentprovider.interfaces.IContentProvider`""" |
109 return self.__parent__.render() |
120 return self.__parent__.render() |
110 |
121 |
111 |
122 |
112 class pagelet_config(object): |
123 class pagelet_config: # pylint: disable=invalid-name |
113 """Function or class decorator used to declare a pagelet""" |
124 """Function or class decorator used to declare a pagelet""" |
114 |
125 |
115 venusian = venusian # for testing injection |
126 venusian = venusian # for testing injection |
116 |
127 |
117 def __init__(self, **settings): |
128 def __init__(self, **settings): |
124 |
135 |
125 def __call__(self, wrapped): |
136 def __call__(self, wrapped): |
126 settings = self.__dict__.copy() |
137 settings = self.__dict__.copy() |
127 depth = settings.pop('_depth', 0) |
138 depth = settings.pop('_depth', 0) |
128 |
139 |
129 def callback(context, name, ob): |
140 def callback(context, name, obj): # pylint: disable=unused-argument |
|
141 """Venusian decorator callback""" |
130 cdict = { |
142 cdict = { |
131 '__name__': settings.get('name'), |
143 '__name__': settings.get('name'), |
132 '__module__': ob.__module__, |
144 '__module__': obj.__module__, |
133 'permission': settings.get('permission') |
145 'permission': settings.get('permission') |
134 } |
146 } |
135 new_class = type(ob.__name__, (ob, Pagelet), cdict) |
147 new_class = type(obj.__name__, (obj, Pagelet), cdict) |
136 |
148 |
137 config = context.config.with_package(info.module) |
149 LOGGER.debug('Registering pagelet view "{0}" for {1} ({2})'.format( |
138 logger.debug('Registering pagelet view "{0}" for {1} ({2})'.format(settings.get('name'), |
150 settings.get('name'), str(settings.get('context', Interface)), str(new_class))) |
139 str(settings.get('context', Interface)), |
151 config = context.config.with_package(info.module) # pylint: disable=no-member |
140 str(new_class))) |
152 registry = settings.get('registry') or config.registry |
141 config.registry.registerAdapter(new_class, |
153 registry.registerAdapter(new_class, |
142 (settings.get('context', Interface), |
154 (settings.get('context', Interface), |
143 settings.get('request_type', IRequest)), |
155 settings.get('request_type', IRequest)), |
144 IPagelet, settings.get('name')) |
156 IPagelet, settings.get('name')) |
145 config.add_view(view=new_class, **settings) |
157 config.add_view(view=new_class, **settings) |
146 |
158 |
147 info = self.venusian.attach(wrapped, callback, category='pyams_pagelet', |
159 info = self.venusian.attach(wrapped, callback, category='pyams_pagelet', |
148 depth=depth + 1) |
160 depth=depth + 1) |
149 |
161 |
150 if info.scope == 'class': |
162 if info.scope == 'class': # pylint: disable=no-member |
151 # if the decorator was attached to a method in a class, or |
163 # if the decorator was attached to a method in a class, or |
152 # otherwise executed at class scope, we need to set an |
164 # otherwise executed at class scope, we need to set an |
153 # 'attr' into the settings if one isn't already in there |
165 # 'attr' into the settings if one isn't already in there |
154 if settings.get('attr') is None: |
166 if settings.get('attr') is None: |
155 settings['attr'] = wrapped.__name__ |
167 settings['attr'] = wrapped.__name__ |
156 |
168 |
157 settings['_info'] = info.codeinfo # fbo "action_method" |
169 settings['_info'] = info.codeinfo # pylint: disable=no-member |
158 return wrapped |
170 return wrapped |