-
Notifications
You must be signed in to change notification settings - Fork 96
/
ProductContext.py
253 lines (205 loc) · 9.24 KB
/
ProductContext.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# 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.
#
##############################################################################
"""Objects providing context for product initialization
"""
import os
from logging import getLogger
import Products
from AccessControl.Permission import registerPermissions
from AccessControl.PermissionRole import PermissionRole
from App.FactoryDispatcher import FactoryDispatcher
from OFS.ObjectManager import ObjectManager
from zope.interface import implementedBy
from ZPublisher import zpublish
from ZPublisher import zpublish_marked
from ZPublisher import zpublish_wrap
if not hasattr(Products, 'meta_types'):
Products.meta_types = ()
if not hasattr(Products, 'meta_classes'):
Products.meta_classes = {}
Products.meta_class_info = {}
_marker = [] # Create a new marker object
LOG = getLogger('ProductContext')
class ProductContext:
def __init__(self, product, app, package):
self.__prod = product
self.__app = app
self.__pack = package
def registerClass(self, instance_class=None, meta_type='',
permission=None, constructors=(),
icon=None, permissions=None, legacy=(),
visibility="Global", interfaces=_marker,
container_filter=None, resources=()):
"""Register a constructor
Keyword arguments are used to provide meta data:
instance_class -- The class of the object that will be created.
meta_type -- The kind of object being created
This appears in add lists. If not specified, then the class
meta_type will be used.
permission -- The permission name for the constructors.
If not specified, then a permission name based on the
meta type will be used.
constructors -- A list of constructor methods
A method can be a callable object with a __name__
attribute giving the name the method should have in the
product, or the method may be a tuple consisting of a
name and a callable object.
The first method will be used as the initial method called
when creating an object.
icon -- No longer used.
permissions -- Additional permissions to be registered
If not provided, then permissions defined in the
class will be registered.
legacy -- A list of legacy methods to be added to ObjectManager
for backward compatibility
visibility -- "Global" if the object is globally visible, None else
interfaces -- a list of the interfaces the object supports
container_filter -- function that is called with an ObjectManager
object as the only parameter, which should return a true object
if the object is happy to be created in that container. The
filter is called before showing ObjectManager's Add list,
and before pasting (after object copy or cut), but not
before calling an object's constructor.
resources -- a sequence of resource specifications
A resource specification is either an object with
a __name__ attribute or a pair consisting of the resource
name and an object.
The resources are put into the ProductFactoryDispather's
namespace under the specified name.
"""
pack = self.__pack
initial = constructors[0]
productObject = self.__prod
pid = productObject.id
if instance_class is not None and not zpublish_marked(instance_class):
zpublish(instance_class)
if permissions:
if isinstance(permissions, str): # You goofed it!
raise TypeError(
'Product context permissions should be a '
'list of permissions not a string', permissions)
for p in permissions:
if isinstance(p, tuple):
p, default = p
registerPermissions(((p, (), default),))
else:
registerPermissions(((p, ()),))
############################################################
# Constructor permission setup
if permission is None:
permission = "Add %ss" % (meta_type or instance_class.meta_type)
if isinstance(permission, tuple):
permission, default = permission
else:
default = ('Manager',)
pr = PermissionRole(permission, default)
registerPermissions(((permission, (), default),))
############################################################
OM = ObjectManager
for method in legacy:
if isinstance(method, tuple):
name, method = method
mname = method.__name__
aliased = 1
else:
name = method.__name__
aliased = 0
if name not in OM.__dict__:
method = zpublish_wrap(method)
setattr(OM, name, method)
setattr(OM, name + '__roles__', pr)
if aliased:
# Set the unaliased method name and its roles
# to avoid security holes. XXX: All "legacy"
# methods need to be eliminated.
setattr(OM, mname, method)
setattr(OM, mname + '__roles__', pr)
if isinstance(initial, tuple):
name, initial = initial
else:
name = initial.__name__
fd = getattr(pack, '__FactoryDispatcher__', None)
if fd is None:
class __FactoryDispatcher__(FactoryDispatcher):
"Factory Dispatcher for a Specific Product"
fd = pack.__FactoryDispatcher__ = __FactoryDispatcher__
if not hasattr(pack, '_m'):
pack._m = AttrDict(fd)
m = pack._m
if interfaces is _marker:
if instance_class is None:
interfaces = ()
else:
interfaces = tuple(implementedBy(instance_class))
Products.meta_types = Products.meta_types + ({
'name': meta_type or instance_class.meta_type,
# 'action': The action in the add drop down in the ZMI. This is
# currently also required by the _verifyObjectPaste
# method of CopyContainers like Folders.
'action': (f'manage_addProduct/{pid}/{name}'),
# 'product': product id
'product': pid,
# 'permission': Guards the add action.
'permission': permission,
# 'visibility': A silly name. Doesn't have much to do with
# visibility. Allowed values: 'Global', None
'visibility': visibility,
# 'interfaces': A tuple of oldstyle and/or newstyle interfaces.
'interfaces': interfaces,
'instance': instance_class,
'container_filter': container_filter
},)
m[name] = zpublish_wrap(initial)
m[name + '__roles__'] = pr
for method in constructors[1:]:
if isinstance(method, tuple):
name, method = method
else:
name = os.path.split(method.__name__)[-1]
if name not in productObject.__dict__:
if not callable(method):
# This code is here because ``Products.CMFCore`` and
# ``Products.CMFPlone`` abuse the ``constructors``
# parameter to register resources violating the explicit
# condition that constructors must be callable.
# It should go away once those components have been fixed.
from warnings import warn
warn("Constructors must be callable; "
"please use `resources` "
"(rather than `constructors`) to register "
"non callable objects",
DeprecationWarning,
2)
m[name] = method
else:
m[name] = zpublish_wrap(method)
m[name + '__roles__'] = pr
for resource in resources:
if isinstance(resource, tuple):
name, resource = resource
else:
name = resource.__name__
if name not in productObject.__dict__:
m[name] = resource
m[name + '__roles__'] = pr
def getApplication(self):
return self.__app
class AttrDict:
def __init__(self, ob):
self.ob = ob
def __contains__(self, name):
return hasattr(self.ob, name)
def __getitem__(self, name):
return getattr(self.ob, name)
def __setitem__(self, name, v):
setattr(self.ob, name, v)