|
1 # |
|
2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net> |
|
3 # All Rights Reserved. |
|
4 # |
|
5 # This software is subject to the provisions of the Zope Public License, |
|
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
|
10 # FOR A PARTICULAR PURPOSE. |
|
11 # |
|
12 |
|
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 |
|
16 # import standard packages |
|
17 import venusian |
|
18 |
|
19 # import interfaces |
|
20 from pyams_viewlet.interfaces import IViewlet, IViewletManager |
|
21 from pyramid.interfaces import IRequest, IView |
|
22 from zope.contentprovider.interfaces import IContentProvider |
|
23 |
|
24 # import packages |
|
25 from pyams_template.template import get_view_template |
|
26 from pyramid.exceptions import ConfigurationError |
|
27 from zope.interface import implementer, Interface |
|
28 |
|
29 |
|
30 @implementer(IContentProvider) |
|
31 class ContentProvider(object): |
|
32 """Template based content provider""" |
|
33 |
|
34 permission = None |
|
35 |
|
36 def __init__(self, context, request, view): |
|
37 self.context = context |
|
38 self.request = request |
|
39 self.view = self.__parent__ = view |
|
40 |
|
41 def update(self): |
|
42 pass |
|
43 |
|
44 def __call__(self): |
|
45 if self.permission and not self.request.has_permission(self.permission): |
|
46 return '' |
|
47 self.update() |
|
48 return self.render() |
|
49 |
|
50 render = get_view_template() |
|
51 |
|
52 |
|
53 class contentprovider_config(object): |
|
54 """Class decorator used to declare a content provider |
|
55 |
|
56 You can provide same arguments as in 'viewlet' ZCML directive: |
|
57 @name = name of the viewlet; may be unique for a given viewlet manager |
|
58 @view = the view class or interface for which viewlet is displayed |
|
59 @for = the context class or interface for which viewlet is displayed |
|
60 @permission = name of a permission required to display the viewlet |
|
61 @layer = request interface required to display the viewlet |
|
62 """ |
|
63 |
|
64 venusian = venusian # for testing injection |
|
65 |
|
66 def __init__(self, **settings): |
|
67 if not settings.get('name'): |
|
68 raise ConfigurationError("You must provide a name for a Viewlet") |
|
69 if 'for_' in settings: |
|
70 if settings.get('context') is None: |
|
71 settings['context'] = settings['for_'] |
|
72 self.__dict__.update(settings) |
|
73 |
|
74 def __call__(self, wrapped): |
|
75 settings = self.__dict__.copy() |
|
76 |
|
77 def callback(context, name, ob): |
|
78 cdict = {'__name__': settings.get('name'), |
|
79 'permission': settings.get('permission')} |
|
80 |
|
81 bases = (ob,) |
|
82 if not IContentProvider.implementedBy(ob): |
|
83 bases = bases + (ContentProvider,) |
|
84 new_class = type('<ContentProvider %s>' % settings.get('name'), bases, cdict) |
|
85 |
|
86 config = context.config.with_package(info.module) |
|
87 config.registry.registerAdapter(new_class, |
|
88 (settings.get('context', Interface), |
|
89 settings.get('layer', IRequest), |
|
90 settings.get('view', IView)), |
|
91 IContentProvider, settings.get('name')) |
|
92 |
|
93 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
|
94 |
|
95 if info.scope == 'class': |
|
96 # if the decorator was attached to a method in a class, or |
|
97 # otherwise executed at class scope, we need to set an |
|
98 # 'attr' into the settings if one isn't already in there |
|
99 if settings.get('attr') is None: |
|
100 settings['attr'] = wrapped.__name__ |
|
101 |
|
102 settings['_info'] = info.codeinfo # fbo "action_method" |
|
103 return wrapped |
|
104 |
|
105 |
|
106 @implementer(IViewlet) |
|
107 class Viewlet(object): |
|
108 """Viewlet adapter class used in meta directive as a mixin class.""" |
|
109 |
|
110 permission = None |
|
111 |
|
112 def __init__(self, context, request, view, manager): |
|
113 self.context = context |
|
114 self.request = request |
|
115 self.__parent__ = view |
|
116 self.manager = manager |
|
117 |
|
118 def update(self): |
|
119 pass |
|
120 |
|
121 render = get_view_template() |
|
122 |
|
123 |
|
124 class viewlet_config(object): |
|
125 """Class decorator used to declare a viewlet |
|
126 |
|
127 You can provide same arguments as in 'viewlet' ZCML directive: |
|
128 @name = name of the viewlet; may be unique for a given viewlet manager |
|
129 @manager = manager class or interface holding the viewlet |
|
130 @view = the view class or interface for which viewlet is displayed |
|
131 @for = the context class or interface for which viewlet is displayed |
|
132 @permission = name of a permission required to display the viewlet |
|
133 @layer = request interface required to display the viewlet |
|
134 @weight = weight of the viewlet when using a weight ordered viewlet manager |
|
135 """ |
|
136 |
|
137 venusian = venusian # for testing injection |
|
138 |
|
139 def __init__(self, **settings): |
|
140 if not settings.get('name'): |
|
141 raise ConfigurationError("You must provide a name for a Viewlet") |
|
142 if 'for_' in settings: |
|
143 if settings.get('context') is None: |
|
144 settings['context'] = settings['for_'] |
|
145 self.__dict__.update(settings) |
|
146 |
|
147 def __call__(self, wrapped): |
|
148 settings = self.__dict__.copy() |
|
149 |
|
150 def callback(context, name, ob): |
|
151 cdict = {'__name__': settings.get('name'), |
|
152 'permission': settings.get('permission'), |
|
153 'weight': settings.get('weight')} |
|
154 |
|
155 bases = (ob,) |
|
156 if not IViewlet.implementedBy(ob): |
|
157 bases = bases + (Viewlet,) |
|
158 new_class = type('<Viewlet %s>' % settings.get('name'), bases, cdict) |
|
159 |
|
160 config = context.config.with_package(info.module) |
|
161 config.registry.registerAdapter(new_class, |
|
162 (settings.get('context', Interface), |
|
163 settings.get('layer', IRequest), |
|
164 settings.get('view', IView), |
|
165 settings.get('manager', IViewletManager)), |
|
166 IViewlet, settings.get('name')) |
|
167 |
|
168 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
|
169 |
|
170 if info.scope == 'class': |
|
171 # if the decorator was attached to a method in a class, or |
|
172 # otherwise executed at class scope, we need to set an |
|
173 # 'attr' into the settings if one isn't already in there |
|
174 if settings.get('attr') is None: |
|
175 settings['attr'] = wrapped.__name__ |
|
176 |
|
177 settings['_info'] = info.codeinfo # fbo "action_method" |
|
178 return wrapped |