Commit 6846d20c authored by Julien Muchembled's avatar Julien Muchembled

* never create temp objects with CMF constructInstance

 * init scripts are never executed on temp objects
 * create constructor for Base and XMLObject temp objects
 * also filter content types for temp objects:
   * new parameter to Folder.newContent to bypass filtering
   * ERP5/Tool/Domain.py needs to bypass filtering
 * fix Delivery_updateAppliedRule to allow creation of portal type 'Internal Packing List' and 'Returned Sale Packing List'

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@21530 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent c63f2474
...@@ -108,7 +108,8 @@ class Domain(Predicate, MetaNode, MetaResource): ...@@ -108,7 +108,8 @@ class Domain(Predicate, MetaNode, MetaResource):
We need a way to know how deep we are in the domain generation We need a way to know how deep we are in the domain generation
to prevent infinite recursion XXX not implemented to prevent infinite recursion XXX not implemented
""" """
klass = tmp_domain_generator = self.newContent(portal_type='Domain Generator', temp_object=1) klass = tmp_domain_generator = self.newContent(
portal_type='Domain Generator', temp_object=1, filter_content_types=0)
script = self.getDomainGeneratorMethodId('') script = self.getDomainGeneratorMethodId('')
return tmp_domain_generator.getDomainGeneratorList(depth=depth, klass=klass, script=script, parent=self) return tmp_domain_generator.getDomainGeneratorList(depth=depth, klass=klass, script=script, parent=self)
...@@ -117,9 +118,9 @@ class Domain(Predicate, MetaNode, MetaResource): ...@@ -117,9 +118,9 @@ class Domain(Predicate, MetaNode, MetaResource):
""" """
We generate temp domain here because we must set an aquisition wrapper We generate temp domain here because we must set an aquisition wrapper
""" """
domain = self.newContent(id=id, portal_type='Domain', temp_object=1) domain = self.newContent(id=id, portal_type='Domain',
domain = domain.__of__(self) temp_object=1, filter_content_types=0)
return domain return domain.__of__(self)
def getChildDomainValueList(self, parent = None, **kw): def getChildDomainValueList(self, parent = None, **kw):
""" """
......
...@@ -78,6 +78,9 @@ applied_rule_dict = {\n ...@@ -78,6 +78,9 @@ applied_rule_dict = {\n
\'Sale Order\': \'default_order_rule\',\n \'Sale Order\': \'default_order_rule\',\n
\'Sale Packing List\': \'default_delivery_rule\',\n \'Sale Packing List\': \'default_delivery_rule\',\n
\'Sale Invoice Transaction\': \'default_invoice_rule\',\n \'Sale Invoice Transaction\': \'default_invoice_rule\',\n
\n
\'Internal Packing List\': None,\n
\'Returned Sale Packing List\': None,\n
\n \n
\'Accounting Rule Cell\': None,\n \'Accounting Rule Cell\': None,\n
\'Accounting Transaction\': None,\n \'Accounting Transaction\': None,\n
......
842 843
\ No newline at end of file \ No newline at end of file
...@@ -410,38 +410,25 @@ class PropertyHolder: ...@@ -410,38 +410,25 @@ class PropertyHolder:
""" """
Return a list of tuple (id, method) for every accessor Return a list of tuple (id, method) for every accessor
""" """
accessor_method_item_list = []
for x, y in self._getItemList(): for x, y in self._getItemList():
if isinstance(y, types.TupleType): if isinstance(y, types.TupleType):
if y is WORKFLOW_METHOD_MARKER or x == '__ac_permissions__':
continue
if len(y) == 0: if len(y) == 0:
raise ValueError("problem at %s %s" % (self._portal_type, x)) raise ValueError("problem at %s %s" % (self._portal_type, x))
result = [] if not issubclass(y[0], Accessor):
#for x in self._getItemList(): continue
#if isinstance(x[1], Accessor): elif not isinstance(y, Accessor):
#result.append(x) continue
#elif isinstance(x[1], types.TupleType): accessor_method_item_list.append((x, y))
#LOG('isinstance', 0, str(x)) return accessor_method_item_list
#if x[1] is not WORKFLOW_METHOD_MARKER and issubclass(x[1][0], Accessor):
#result.append(x)
#return result
return [x for x in self._getItemList() if isinstance(x[1], Accessor)
or (isinstance(x[1], types.TupleType)
and x[1] is not WORKFLOW_METHOD_MARKER
and x[0] != '__ac_permissions__'
and issubclass(x[1][0], Accessor))]
def getAccessorMethodIdList(self): def getAccessorMethodIdList(self):
""" """
Return the list of accessor IDs Return the list of accessor IDs
""" """
for x, y in self._getItemList(): return [ x[0] for x in self.getAccessorMethodItemList() ]
if isinstance(y, types.TupleType):
if len(y) == 0:
raise ValueError("problem at %s %s" % (self._portal_type, x))
return [x[0] for x in self._getItemList() if isinstance(x[1], Accessor)
or (isinstance(x[1], types.TupleType)
and x[1] is not WORKFLOW_METHOD_MARKER
and x[0] != '__ac_permissions__'
and issubclass(x[1][0], Accessor))]
def getWorkflowMethodItemList(self): def getWorkflowMethodItemList(self):
""" """
......
...@@ -100,11 +100,19 @@ class FolderMixIn(ExtensionClass.Base): ...@@ -100,11 +100,19 @@ class FolderMixIn(ExtensionClass.Base):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declarePublic('isTempObject')
def isTempObject(self):
"""Return true if self is an instance of a temporary document class.
"""
# Note: Folder inherits from Base and FolderMixIn but Base has priority.
return 0
security.declarePublic('newContent') security.declarePublic('newContent')
def newContent(self, id=None, portal_type=None, id_group=None, def newContent(self, id=None, portal_type=None, id_group=None,
default=None, method=None, immediate_reindex=0, default=None, method=None, immediate_reindex=0,
container=None, created_by_builder=0, activate_kw=None, container=None, created_by_builder=0, activate_kw=None,
is_indexable=None, temp_object=0, reindex_kw=None, **kw): is_indexable=None, temp_object=0, reindex_kw=None,
filter_content_types=1, **kw):
"""Creates a new content. """Creates a new content.
This method is public, since TypeInformation.constructInstance will perform This method is public, since TypeInformation.constructInstance will perform
the security check. the security check.
...@@ -112,29 +120,41 @@ class FolderMixIn(ExtensionClass.Base): ...@@ -112,29 +120,41 @@ class FolderMixIn(ExtensionClass.Base):
pt = self._getTypesTool() pt = self._getTypesTool()
if container is None: if container is None:
container = self container = self
if id is None and not temp_object: temp_container = container.isTempObject()
# The only case where the id is unused (because the new object is not added
# to its parent) is when a temp object is created inside a non-temp object.
if id is None and (temp_container or not temp_object):
new_id = str(container.generateNewId( id_group=id_group, new_id = str(container.generateNewId( id_group=id_group,
default=default, default=default,
method=method)) method=method))
else: else:
new_id = str(id) new_id = str(id)
if portal_type is None: if portal_type is None:
# XXX This feature is very confusing # XXX This feature is very confusing
# And made the code more difficult to update # And made the code more difficult to update
portal_type = container.allowedContentTypes()[0].id portal_type = container.allowedContentTypes()[0].id
elif filter_content_types:
type_info = pt.getTypeInfo(container)
if type_info is not None and not type_info.allowType(portal_type) and \
'portal_trash' not in container.getPhysicalPath():
raise ValueError('Disallowed subobject type: %s' % portal_type)
# we get an object from factory only for first temp container object # Use the factory even if the parent is already a temp object,
# otherwise we get an id so we can use the classic way # like this we do not call the classic way, indeed, we do not
if temp_object and not getattr(container, 'isTempObject', lambda: 0)(): # need to call init script, security settings on temp objects.
from Products.ERP5Type import Document if temp_object or temp_container:
factory_name = 'newTemp%s' %(portal_type.replace(' ', '')) type_info = pt.getTypeInfo(portal_type)
m = getattr(Document, factory_name) if not type_info.factory or not type_info.factory.startswith('add'):
new_instance = m(container, new_id) raise ValueError('Product factory for %s is invalid: %s' %
(portal_type, type_info.factory))
p = container.manage_addProduct[type_info.product]
m = getattr(p, 'newTemp' + type_info.factory[3:])
new_instance = m(new_id, container)
if hasattr(new_instance, '_setPortalTypeName'):
new_instance._setPortalTypeName(portal_type)
else: else:
myType = pt.getTypeInfo(container)
if myType is not None and not myType.allowType( portal_type ) and \
'portal_trash' not in container.getPhysicalPath():
raise ValueError('Disallowed subobject type: %s' % portal_type)
pt.constructContent( type_name=portal_type, pt.constructContent( type_name=portal_type,
container=container, container=container,
id=new_id, id=new_id,
......
...@@ -249,27 +249,6 @@ class ERP5TypeInformationMixIn( FactoryTypeInformation, ...@@ -249,27 +249,6 @@ class ERP5TypeInformationMixIn( FactoryTypeInformation,
return default return default
def _getFactoryMethod(self, container, check_security=1):
if not self.product or not self.factory:
raise ValueError, ('Product factory for %s was undefined' %
self.getId())
p = container.manage_addProduct[self.product]
if hasattr(container, 'isTempObject') and container.isTempObject():
factory_name = self.factory.replace('add', 'newTemp') # We suppose here
# that methods are names addClass or newTempClass
# Prefix should be moved to a central place.
m = getattr(p, factory_name, None)
else:
m = getattr(p, self.factory, None)
if m is None:
raise ValueError, ('Product factory for %s was invalid' %
self.getId())
if not check_security:
return m
if getSecurityManager().validate(p, p, self.factory, m):
return m
raise AccessControl_Unauthorized( 'Cannot create %s' % self.getId() )
security.declarePublic('constructInstance') security.declarePublic('constructInstance')
def constructInstance( self, container, id, def constructInstance( self, container, id,
created_by_builder=0, *args, **kw ): created_by_builder=0, *args, **kw ):
......
...@@ -367,17 +367,15 @@ class TempDocumentConstructor(DocumentConstructor): ...@@ -367,17 +367,15 @@ class TempDocumentConstructor(DocumentConstructor):
self.klass = TempDocument self.klass = TempDocument
def __call__(self, folder, id, REQUEST=None, **kw): def __call__(self, folder, id, REQUEST=None, **kw):
# CMF constructInstance is never used to build temp objects
# so we never return the id.
o = self.klass(id) o = self.klass(id)
if folder.isTempObject():
folder._setObject(id, o)
o = o.__of__(folder)
if kw: if kw:
o.__of__(folder)._edit(force_update=1, **kw) o._edit(force_update=1, **kw)
isTempObject = getattr(folder, 'isTempObject', None) return o
if isTempObject is not None and isTempObject():
folder._setObject(id, o)# Temp Object in Temp Object should use containment
return id # return id to be compatible with CMF constructInstance
else: # Temp Object in Persistent Object should use acquisition
o = o.__of__(folder)
return o # We should return id if called on a Factory Dispatcher
# and return o if called on a container
python_file_parser = re.compile('^(.*)\.py$') python_file_parser = re.compile('^(.*)\.py$')
...@@ -869,6 +867,9 @@ def initializeProduct( context, ...@@ -869,6 +867,9 @@ def initializeProduct( context,
if hasattr(content_class, 'add' + content_class.__name__): if hasattr(content_class, 'add' + content_class.__name__):
extra_content_constructors += [ extra_content_constructors += [
getattr(content_class, 'add' + content_class.__name__)] getattr(content_class, 'add' + content_class.__name__)]
if hasattr(content_class, 'newTemp' + content_class.__name__):
extra_content_constructors += [
getattr(content_class, 'newTemp' + content_class.__name__)]
# Define FactoryTypeInformations for all content classes # Define FactoryTypeInformations for all content classes
contentFactoryTypeInformations = [] contentFactoryTypeInformations = []
...@@ -993,12 +994,19 @@ def setDefaultConstructor(klass): ...@@ -993,12 +994,19 @@ def setDefaultConstructor(klass):
""" """
Create the default content creation method Create the default content creation method
""" """
if not hasattr(klass, 'add' + klass.__name__): document_constructor_name = 'add' + klass.__name__
if not hasattr(klass, document_constructor_name):
document_constructor = DocumentConstructor(klass) document_constructor = DocumentConstructor(klass)
document_constructor_name = "add%s" % klass.__name__
setattr(klass, document_constructor_name, document_constructor) setattr(klass, document_constructor_name, document_constructor)
document_constructor.__name__ = document_constructor_name document_constructor.__name__ = document_constructor_name
temp_document_constructor_name = 'newTemp' + klass.__name__
if not hasattr(klass, temp_document_constructor_name):
temp_document_constructor = TempDocumentConstructor(klass)
setattr(klass, temp_document_constructor_name, temp_document_constructor)
temp_document_constructor.__name__ = temp_document_constructor_name
klass.security.declarePublic(temp_document_constructor_name)
def createExpressionContext(object, portal=None): def createExpressionContext(object, portal=None):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment