Commit d8961c51 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Allow migration of {Interface,Mixin,Module,Tool} from...

ZODB Components: Allow migration of {Interface,Mixin,Module,Tool} from Business Template UI and on all Products (not only Products.ERP5).

This introduces the following new ZODB Components:
  + Module Component: Non-Documents/non-persistent classes of modules usually
    found at the top-level of Products (eg Products.ERP5.XXX) on FS. Considering
    that all other Components types are actually Modules, make it the base class.
  + Tool Component: Tool directory of Products on FS (eg Products.ERP5.Tool.XXX).
    => DiffTool and CallableTool are now 'Tool Component' instead of plain
       'Document Component' and properly registered as Tools like FS Products Tool.

Skip CMFActivity and HBTreeFolder2 Products for now in migration View for now as
almost many Portal Type classes have ActiveObject or HBTreeFolder2 in their MRO
and these Products will be done at the end anyway...
parent a4e63da9
......@@ -89,6 +89,7 @@ from urllib import quote, unquote
from difflib import unified_diff
import posixpath
import transaction
import inspect
import threading
from ZODB.broken import Broken, BrokenModified
......@@ -138,6 +139,7 @@ SEPARATELY_EXPORTED_PROPERTY_DICT = {
"Interface Component": ("py", 0, "text_content"),
"OOoTemplate": ("oot", 1, "_text"),
"Mixin Component": ("py", 0, "text_content"),
"Module Component": ("py", 0, "text_content"),
"PDF": ("pdf", 0, "data"),
"PDFForm": ("pdf", 0, "data"),
"PyData Script": ("py", 0, "_body"),
......@@ -148,6 +150,7 @@ SEPARATELY_EXPORTED_PROPERTY_DICT = {
"SQL Method": ("sql", 0, "src"),
"Test Component": ("py", 0, "text_content"),
"Test Page": (None, 0, "text_content"),
"Tool Component": ("py", 0, "text_content"),
"Web Page": (None, 0, "text_content"),
"Web Script": (None, 0, "text_content"),
"Web Style": (None, 0, "text_content"),
......@@ -4262,6 +4265,12 @@ class _ZodbComponentTemplateItem(ObjectTemplateItem):
self.portal_components.reset(force=True,
reset_portal_type_at_transaction_boundary=True)
from Products.ERP5Type.Core.ModuleComponent import ModuleComponent
class ModuleComponentTemplateItem(_ZodbComponentTemplateItem):
@staticmethod
def _getZodbObjectId(id):
return ModuleComponent.getIdPrefix() + '.' + id
from Products.ERP5Type.Core.InterfaceComponent import InterfaceComponent
class InterfaceTemplateItem(_ZodbComponentTemplateItem):
@staticmethod
......@@ -4274,6 +4283,12 @@ class MixinTemplateItem(_ZodbComponentTemplateItem):
def _getZodbObjectId(id):
return MixinComponent.getIdPrefix() + '.' + id
from Products.ERP5Type.Core.ToolComponent import ToolComponent
class ToolComponentTemplateItem(_ZodbComponentTemplateItem):
@staticmethod
def _getZodbObjectId(id):
return ToolComponent.getIdPrefix() + '.' + id
from Products.ERP5Type.Core.DocumentComponent import DocumentComponent
class DocumentTemplateItem(FilesystemToZodbTemplateItem,
_ZodbComponentTemplateItem):
......@@ -4370,7 +4385,6 @@ class DocumentTemplateItem(FilesystemToZodbTemplateItem,
afterUninstall = _ZodbComponentTemplateItem.afterUninstall
from Products.ERP5Type.Core.ExtensionComponent import ExtensionComponent
class ExtensionTemplateItem(DocumentTemplateItem):
"""
Extensions are now stored in ZODB rather than on the filesystem. However,
......@@ -5243,10 +5257,14 @@ Business Template is a set of definitions, such as skins, portal types and categ
self._catalog_security_uid_column_item = \
CatalogSecurityUidColumnTemplateItem(
self.getTemplateCatalogSecurityUidColumnList())
self._module_component_item = \
ModuleComponentTemplateItem(self.getTemplateModuleComponentIdList())
self._interface_item = \
InterfaceTemplateItem(self.getTemplateInterfaceIdList())
self._mixin_item = \
MixinTemplateItem(self.getTemplateMixinIdList())
self._tool_component_item = \
ToolComponentTemplateItem(self.getTemplateToolComponentIdList())
security.declareProtected(Permissions.ManagePortal, 'build')
def build(self, no_action=0, update_revision=True):
......@@ -5982,9 +6000,11 @@ Business Template is a set of definitions, such as skins, portal types and categ
'Product' : '_product_item',
'PropertySheet' : '_property_sheet_item',
'Constraint' : '_constraint_item',
'ModuleComponent' : '_module_component_item',
'Document' : '_document_item',
'Interface': '_interface_item',
'Mixin': '_mixin_item',
'ToolComponent' : '_tool_component_item',
'Extension' : '_extension_item',
'Test' : '_test_item',
'Role' : '_role_item',
......@@ -6095,7 +6115,9 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Text objects (no need to export them into XML)
# XXX Bad naming
item_list_3 = ['_document_item', '_interface_item', '_mixin_item',
item_list_3 = ['_module_component_item',
'_document_item', '_interface_item', '_mixin_item',
'_tool_component_item',
'_property_sheet_item',
'_constraint_item', '_extension_item',
'_test_item', '_message_translation_item',]
......@@ -6341,13 +6363,48 @@ Business Template is a set of definitions, such as skins, portal types and categ
setattr(self, 'template_portal_type_base_category', ())
return
@staticmethod
def _getAllFilesystemModuleFromPortalTypeIdList(portal_type_id_list):
def _getWorkingCopyPathList(self):
working_copy_list = self.getPortalObject().portal_preferences.getPreferredWorkingCopyList([])
if not working_copy_list:
raise RuntimeError("No 'Working Copies' set in Preferences")
return [ os.path.realpath(p) for p in working_copy_list ]
def _checkFilesystemModulePath(self,
module_obj,
working_copy_path_list):
"""
Return the path of the given module iff its path is in Working Copies
"""
try:
module_path = inspect.getsourcefile(module_obj)
except TypeError:
# No file, builtin or 'erp5' dynamic module
return None
else:
# Canonicalize all paths before comparing (at the same time this will
# take care of trailing '/')
module_realpath = os.path.realpath(module_path)
for working_copy_path in working_copy_path_list:
working_copy_path = os.path.realpath(working_copy_path)
if working_copy_path.endswith('bt5'):
working_copy_path = working_copy_path[:-3]
if module_realpath.startswith(working_copy_path):
# Product
if module_path.endswith('/__init__.py'):
return module_path.rsplit('/', 1)[0]
else:
return module_path
return None
def _getAllFilesystemModuleFromPortalTypeIdList(self, portal_type_id_list):
import erp5.portal_type
import inspect
import Products.ERP5Type
import zope.interface
product_base_path = inspect.getfile(Products.ERP5Type).rsplit('/', 2)[0]
working_copy_path_list = self._getWorkingCopyPathList()
seen_cls_set = set()
for portal_type in portal_type_id_list:
# According to ObjectTemplateItem.__init__, this could happen (see
......@@ -6366,24 +6423,22 @@ Business Template is a set of definitions, such as skins, portal types and categ
error=True)
continue
for cls in portal_type_cls.mro():
if (not cls.__module__.startswith('erp5.') and
cls not in seen_cls_set):
seen_cls_set.add(cls)
try:
cls_path = inspect.getfile(cls)
except TypeError:
pass
else:
if cls_path.startswith(product_base_path):
cls_name = cls.__name__
cls_module = cls.__module__
yield cls_name, cls_module, cls_path
for cls in (tuple(zope.interface.implementedBy(portal_type_cls)) +
portal_type_cls.mro()):
if cls in seen_cls_set:
continue
seen_cls_set.add(cls)
cls_module_filepath = self._checkFilesystemModulePath(
inspect.getmodule(cls),
working_copy_path_list)
if cls_module_filepath is not None:
cls_module_name = cls.__module__
yield cls.__name__, cls.__module__, cls_module_filepath
security.declareProtected(Permissions.ManagePortal,
'getMigratableSourceCodeFromFilesystemList')
def getMigratableSourceCodeFromFilesystemList(self,
current_bt_only=False,
*args,
**kwargs):
"""
......@@ -6430,35 +6485,112 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Inspect Portal Types classes mro() of this Business Template to find
# Products Documents to migrate by default
portal_type_module_set = set(
portal_type_module_filepath_set = set([
filepath for _, _, filepath in
self._getAllFilesystemModuleFromPortalTypeIdList(
self.getTemplatePortalTypeIdList()))
self.getTemplatePortalTypeIdList())])
working_copy_path_list = self._getWorkingCopyPathList()
import Products
for product_name, product_obj in inspect.getmembers(Products,
inspect.ismodule):
if (product_name[0] == '_' or
# Returned by inspect.getmembers()
product_name == 'this_module' or
product_name in (
# Never going to be migrated (bootstrap)
'ERP5Type',
# Probably going to be migrated but at the end and should not be
# done for now (especially ActiveObject and HBTreeFolder2
# classes found in the MRO of most classes)
'CMFActivity', 'HBTreeFolder2')):
continue
# XXX: Only migrate Documents in ERP5 for the moment...
import Products.ERP5.Document
for name, obj in Products.ERP5.Document.__dict__.iteritems():
if not name.startswith('_') and inspect.ismodule(obj):
source_reference = obj.__name__
product_base_path = self._checkFilesystemModulePath(
product_obj,
working_copy_path_list)
if product_base_path is None:
continue
migrate = ((name, source_reference, inspect.getfile(obj))
in portal_type_module_set)
if current_bt_only and not migrate:
# 'Module Component': Only handle Product top-level modules
for submodule_name, submodule_obj in inspect.getmembers(product_obj,
inspect.ismodule):
if (submodule_name[0] == '_' or
submodule_name in ('this_module', 'Permissions')):
continue
obj = __newTempComponent(portal_type='Document Component',
reference=name,
source_reference=source_reference,
migrate=migrate)
if not current_bt_only:
import Products.ERP5.tests
from glob import iglob
for test_path in iglob("%s/test*.py" %
inspect.getfile(Products.ERP5.tests).rsplit('/', 1)[0]):
reference = test_path.rsplit('/', 1)[1][:-3]
obj = __newTempComponent(portal_type='Test Component',
reference=reference,
source_reference="Products.ERP5.tests." + reference)
try:
submodule_filepath = inspect.getsourcefile(submodule_obj)
except TypeError:
# No file, builtin?
continue
if submodule_filepath and submodule_filepath.rsplit('/', 1)[0] == product_base_path:
source_reference = submodule_obj.__name__
migrate = submodule_filepath in portal_type_module_filepath_set
obj = __newTempComponent(portal_type='Module Component',
reference=submodule_name,
source_reference=source_reference,
migrate=migrate)
# {Document,interfaces,mixin,Tool,tests} directories
for directory_name, component_portal_type in (
('Document', 'Document Component'),
('interfaces', 'Interface Component'),
('mixin', 'Mixin Component'),
('Tool', 'Tool Component'),
('tests', 'Test Component')):
submodule_name = '%s.%s' % (product_obj.__name__, directory_name)
for filepath in glob.iglob("%s/%s/*.py" % (product_base_path,
directory_name)):
subsubmodule_name = os.path.splitext(os.path.basename(filepath))[0]
if subsubmodule_name == '__init__':
continue
subsubmodule_portal_type = component_portal_type
source_reference = "%s.%s" % (submodule_name, subsubmodule_name)
migrate = filepath in portal_type_module_filepath_set
if component_portal_type == 'Test Component':
# For non test classes (Mixin, utils...)
if not subsubmodule_name.startswith('test'):
subsubmodule_portal_type = 'Module Component'
# FS: Products/ERP5ShortMessage/interfaces/sms_sending_gateway.py: ISmsSendingGateway
# => ZODB Component Reference: ISmsSendingGateway
elif component_portal_type == 'Interface Component':
# Generally: foo_bar.py => IFooBar, but to avoid quirks (such as
# 'sql_foo.py' => 'ISQLFoo'), get the Interface class __name__
try:
interface_module = __import__(source_reference, {}, {}, source_reference)
except ImportError, e:
LOG("BusinessTemplate", WARNING,
"Skipping %s: Cannot be imported (%s)" % (filepath, e))
continue
from zope.interface.interface import InterfaceClass
interface_class_name = None
for _, m in inspect.getmembers(interface_module):
if (isinstance(m, InterfaceClass) and
# Local definition only
m.__module__ == interface_module.__name__):
if interface_class_name is not None:
# Do not try to be clever, just let the developer fix the problem
LOG("BusinessTemplate", WARNING,
"Skipping %s: More than one InterfaceClass defined" % filepath)
interface_class_name = None
break
else:
interface_class_name = m.__name__
if interface_class_name is None:
continue
subsubmodule_name = interface_class_name
obj = __newTempComponent(portal_type=subsubmodule_portal_type,
reference=subsubmodule_name,
source_reference=source_reference,
migrate=migrate)
# Automatically select ZODB Components to be migrated in Migration Dialog
selection_name = kwargs.get('selection_name')
......@@ -6490,13 +6622,18 @@ Business Template is a set of definitions, such as skins, portal types and categ
list_selection_name = kw.get('list_selection_name')
migrated_product_module_set = set()
template_module_component_id_set = set(self.getTemplateModuleComponentIdList())
template_mixin_id_set = set(self.getTemplateMixinIdList())
template_interface_id_set = set(self.getTemplateInterfaceIdList())
template_document_id_set = set(self.getTemplateDocumentIdList())
template_tool_component_id_set = set(self.getTemplateToolComponentIdList())
template_extension_id_set = set(self.getTemplateExtensionIdList())
template_test_id_set = set(self.getTemplateTestIdList())
if list_selection_name is None:
temp_obj_list = self.getMigratableSourceCodeFromFilesystemList(
current_bt_only=True)
# Programmatically called, not through the UI
temp_obj_list = [ temp_obj for temp_obj in self.getMigratableSourceCodeFromFilesystemList()
if temp_obj.migrate ]
else:
from base64 import b64decode
import cPickle
......@@ -6521,13 +6658,22 @@ Business Template is a set of definitions, such as skins, portal types and categ
return
filesystem_zodb_module_mapping_set = set()
for temp_obj in temp_obj_list:
source_reference = temp_obj.getSourceReference()
if source_reference is not None:
filesystem_zodb_module_mapping_set.add(
(source_reference, "%s.%s" % (temp_obj._getDynamicModuleNamespace(),
temp_obj.getReference())))
for temp_obj in temp_obj_list:
source_reference = temp_obj.getSourceReference()
try:
obj = temp_obj.importFromFilesystem(component_tool,
temp_obj.getReference(),
version,
source_reference)
source_reference,
filesystem_zodb_module_mapping_set)
except Exception, e:
LOG("BusinessTemplate", WARNING,
"Could not import component '%s' ('%s') from the filesystem" %
......@@ -6542,6 +6688,14 @@ Business Template is a set of definitions, such as skins, portal types and categ
id_set = template_extension_id_set
elif portal_type == 'Test Component':
id_set = template_test_id_set
elif portal_type == 'Mixin Component':
id_set = template_mixin_id_set
elif portal_type == 'Module Component':
id_set = template_module_component_id_set
elif portal_type == 'Interface Component':
id_set = template_interface_id_set
elif portal_type == 'Tool Component':
id_set = template_tool_component_id_set
# 'Document Component'
else:
id_set = template_document_id_set
......@@ -6567,12 +6721,19 @@ Business Template is a set of definitions, such as skins, portal types and categ
transaction.abort()
raise RuntimeError(message)
self.setTemplateModuleComponentIdList(sorted(template_module_component_id_set))
self.setTemplateMixinIdList(sorted(template_mixin_id_set))
self.setTemplateInterfaceIdList(sorted(template_interface_id_set))
self.setTemplateDocumentIdList(sorted(template_document_id_set))
self.setTemplateToolComponentIdList(sorted(template_tool_component_id_set))
self.setTemplateExtensionIdList(sorted(template_extension_id_set))
self.setTemplateTestIdList(sorted(template_test_id_set))
# This will trigger a reset so that Portal Types mro() can be checked
# after migration for filesystem Products modules still being used
#
# TODO-arnau: checkPythonSource code done twice (importFromFilesystem()
# and newContent() through Interaction Workflow)
transaction.commit()
still_used_list_dict = {}
......
......@@ -69,9 +69,11 @@ item_name_list = (
'registered_version_priority_selection',
'workflow',
'product',
'module_component',
'document',
'interface',
'mixin',
'tool_component',
'property_sheet',
'constraint',
'extension',
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ComponentMixin_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object is not None and not object.isWebMode()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ComponentMixin_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object is not None and not object.isWebMode()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -53,7 +53,9 @@
<item>Extension Component</item>
<item>Interface Component</item>
<item>Mixin Component</item>
<item>Module Component</item>
<item>Test Component</item>
<item>Tool Component</item>
</portal_type>
<portal_type id="Contribution Registry Tool">
<item>Contribution Predicate</item>
......
......@@ -47,6 +47,9 @@
<portal_type id="Mixin Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Module Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Property Existence Constraint">
<item>ConstraintType</item>
</portal_type>
......@@ -79,6 +82,9 @@
<portal_type id="Test Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Tool Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Trash Bin">
<item>Base</item>
<item>SimpleItem</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_property_domain_dict</string> </key>
<value>
<dictionary>
<item>
<key> <string>short_title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>web_page.png</string> </value>
</item>
<item>
<key> <string>content_meta_type</string> </key>
<value> <string>ERP5 Text Document</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A Module Component is any non-persistent Module containing classes definitions (used to be found at the root of Products).</string> </value>
</item>
<item>
<key> <string>factory</string> </key>
<value> <string>addDocumentComponent</string> </value>
</item>
<item>
<key> <string>filter_content_types</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>ModuleComponent</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>short_title</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>title</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_property_domain_dict</string> </key>
<value>
<dictionary>
<item>
<key> <string>short_title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>web_page.png</string> </value>
</item>
<item>
<key> <string>content_meta_type</string> </key>
<value> <string>ERP5 Text Document</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A Tool Component as used to be found in Products.XXX.Tool</string> </value>
</item>
<item>
<key> <string>factory</string> </key>
<value> <string>addDocumentComponent</string> </value>
</item>
<item>
<key> <string>filter_content_types</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Tool Component</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>ToolComponent</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>short_title</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>title</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -123,6 +123,10 @@
<type>Mixin Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
<chain>
<type>Module Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
<chain>
<type>Predicate</type>
<workflow>edit_workflow</workflow>
......@@ -175,4 +179,8 @@
<type>Test Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
<chain>
<type>Tool Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
</workflow_chain>
\ No newline at end of file
......@@ -64,11 +64,13 @@
<list>
<string>my_template_role_list</string>
<string>my_template_site_property_id_list</string>
<string>my_template_module_component_id_list</string>
<string>my_template_interface_id_list</string>
<string>my_template_mixin_id_list</string>
<string>my_template_document_id_list</string>
<string>my_template_property_sheet_id_list</string>
<string>my_template_extension_id_list</string>
<string>my_template_tool_component_id_list</string>
<string>my_template_tool_id_list</string>
<string>my_template_preference_list</string>
<string>my_template_update_tool</string>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="LinesField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_template_module_component_id_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Module Components</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string> </string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="LinesField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_template_tool_component_id_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Tool Components</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string> </string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -2,31 +2,27 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
<global name="Tool Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>CallableTool</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A tool that can be used to add scripts and other callable methods (including ZSQL templates and HTML templates) to ERP5. It replaces portal_skins</string> </value>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.CallableTool</string> </value>
<value> <string>tool.erp5.CallableTool</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
<value> <string>Tool Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
......@@ -53,28 +49,13 @@
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
......@@ -87,7 +68,7 @@
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
......@@ -96,7 +77,7 @@
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
......
......@@ -2,31 +2,27 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
<global name="Tool Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>DiffTool</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A tool than can be used to Diff any 2 objects of same module.</string> </value>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.DiffTool</string> </value>
<value> <string>tool.erp5.DiffTool</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
<value> <string>Tool Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
......@@ -53,28 +49,13 @@
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
......@@ -87,7 +68,7 @@
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
......@@ -96,7 +77,7 @@
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
......
......@@ -74,7 +74,9 @@
<string>Extension Component</string>
<string>Interface Component</string>
<string>Mixin Component</string>
<string>Module Component</string>
<string>Test Component</string>
<string>Tool Component</string>
</list>
</value>
</item>
......
......@@ -73,7 +73,9 @@
<string>Extension Component</string>
<string>Interface Component</string>
<string>Mixin Component</string>
<string>Module Component</string>
<string>Test Component</string>
<string>Tool Component</string>
</list>
</value>
</item>
......
......@@ -89,6 +89,7 @@ Interface Component | view
Memcached Plugin | view
Memcached Tool | view
Mixin Component | view
Module Component | view
Predicate | view
Preference Tool Type | jump_property_sheets
Preference Tool Type | view
......@@ -147,6 +148,7 @@ Template Tool | upgrade_from_repository
Template Tool | view
Test Component | run_live_test
Test Component | view
Tool Component | view
Trash Bin | jump_bt5
Trash Bin | view
Trash Folder | view
......
document.erp5.DiffTool
document.erp5.ScriptConstraint
document.erp5.TransformOdtToDocx
document.erp5.TransformOdtToHtml
......@@ -27,5 +26,4 @@ document.erp5.TransformPptxToOdp
document.erp5.TransformPptxToPpty
document.erp5.TransformPptyToPptx
document.erp5.TransformImageToPcx
document.erp5.TransformImageToBmp
document.erp5.CallableTool
\ No newline at end of file
document.erp5.TransformImageToBmp
\ No newline at end of file
......@@ -23,7 +23,9 @@ Component Tool | Document Component
Component Tool | Extension Component
Component Tool | Interface Component
Component Tool | Mixin Component
Component Tool | Module Component
Component Tool | Test Component
Component Tool | Tool Component
Contribution Registry Tool | Contribution Predicate
Domain Tool | Base Domain
Domain | Domain
......
......@@ -53,6 +53,7 @@ Mapped Value
Memcached Plugin
Memcached Tool
Mixin Component
Module Component
Movement
Notification Tool
Order Tool
......@@ -85,6 +86,7 @@ TALES Constraint
Template Tool
Test Component
Test Tool
Tool Component
Trash Bin
Trash Folder
Trash Tool
......
......@@ -14,6 +14,7 @@ Document Component | SortIndex
Extension Component | SortIndex
Interface Component | SortIndex
Mixin Component | SortIndex
Module Component | SortIndex
Property Existence Constraint | ConstraintType
Property Type Validity Constraint | ConstraintType
Python Script | CatalogFilter
......@@ -29,6 +30,7 @@ Simulation Movement | SortIndex
String Attribute Match Constraint | ConstraintType
TALES Constraint | ConstraintType
Test Component | SortIndex
Tool Component | SortIndex
Trash Bin | Base
Trash Bin | SimpleItem
Trash Bin | Task
\ No newline at end of file
......@@ -40,6 +40,9 @@ Memcached Plugin | memcached_plugin_interaction_workflow
Mixin Component | component_validation_workflow
Mixin Component | dynamic_class_generation_interaction_workflow
Mixin Component | edit_workflow
Module Component | component_validation_workflow
Module Component | dynamic_class_generation_interaction_workflow
Module Component | edit_workflow
Predicate | edit_workflow
Preference | edit_workflow
Preference | preference_workflow
......@@ -56,4 +59,7 @@ System Preference | preference_workflow
TALES Constraint | dynamic_class_generation_interaction_workflow
Test Component | component_validation_workflow
Test Component | dynamic_class_generation_interaction_workflow
Test Component | edit_workflow
\ No newline at end of file
Test Component | edit_workflow
Tool Component | component_validation_workflow
Tool Component | dynamic_class_generation_interaction_workflow
Tool Component | edit_workflow
\ No newline at end of file
tool.erp5.CallableTool
tool.erp5.DiffTool
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A list of IDs of Module (not a Tool, Document, Interface or Mixin) ZODB Components</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_module_component_id_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: ()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A list of IDs of Tool ZODB Components</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_tool_component_id_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: ()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -7840,6 +7840,7 @@ class _ProductMigrationTemplateItemMixin:
"""
sequence_list = SequenceList()
sequence_string = """
SetPreferredWorkingCopyList
CreateProductDocumentAndPortalType
CreateNewBusinessTemplate
UseExportBusinessTemplate
......@@ -8189,6 +8190,30 @@ class _LocalTemplateItemMixin:
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def stepSetPreferredWorkingCopyList(self, sequence=None, **kw):
"""
TODO: Merge with Zuite_setPreference (ERP5TypeFunctionalTestCase)?
"""
pref = getattr(self.portal.portal_preferences,
"testBusinessTemplate_test_preference",
None)
if pref is None:
pref = self.portal.portal_preferences.newContent(
id="testBusinessTemplate_test_preference",
portal_type="Preference",
priority=1)
import inspect
import Products.ERP5
erp5_product_directory = os.path.realpath(
inspect.getsourcefile(Products.ERP5)).rsplit('/', 1)[0]
pref.setPreferredWorkingCopyList(
[erp5_product_directory.rsplit('/', 2)[0] + '/bt5',
erp5_product_directory + '/bootstrap'])
if pref.getPreferenceState() == 'disabled':
pref.enable()
def stepCopyAndMigrateDocumentBusinessTemplate(self, sequence=None, **kw):
"""
Simulate migration from filesystem to ZODB
......@@ -8243,6 +8268,7 @@ class _LocalTemplateItemMixin:
"""
sequence_list = SequenceList()
sequence_string = '\
SetPreferredWorkingCopyList \
CreateDocument \
CreateNewBusinessTemplate \
UseExportBusinessTemplate \
......@@ -8313,6 +8339,7 @@ class _LocalTemplateItemMixin:
def test_BusinessTemplateUpgradeDocumentFromFilesystemToZodb(self):
sequence_list = SequenceList()
sequence_string = """
SetPreferredWorkingCopyList
CreateDocument
CreateNewBusinessTemplate
UseExportBusinessTemplate
......
......@@ -27,8 +27,8 @@
#
##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from Products.ERP5Type.Core.ModuleComponent import ModuleComponent
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
......@@ -37,7 +37,7 @@ import zope.interface
import re
from Products.ERP5Type.interfaces.component import IComponent
class DocumentComponent(ComponentMixin, TextContentHistoryMixin):
class DocumentComponent(ModuleComponent):
"""
ZODB Component for Documents in bt5 only for now (which used to be installed
in INSTANCE_HOME/Document) but this will also be used later on for Documents
......
......@@ -27,15 +27,15 @@
#
##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from Products.ERP5Type.Core.ModuleComponent import ModuleComponent
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
import zope.interface
from Products.ERP5Type.interfaces.component import IComponent
class ExtensionComponent(ComponentMixin, TextContentHistoryMixin):
class ExtensionComponent(ModuleComponent):
"""
ZODB Component for Extensions previously defined in the bt5 and installed in
INSTANCE_HOME/Extensions
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
import zope.interface
from Products.ERP5Type.interfaces.component import IComponent
class ModuleComponent(ComponentMixin, TextContentHistoryMixin):
"""
ZODB Component for Modules, eg non-Documents from Products, and the base
class for all other Components
"""
meta_type = 'ERP5 Module Component'
portal_type = 'Module Component'
zope.interface.implements(IComponent)
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@staticmethod
def _getFilesystemPath():
# TODO-arnau: useful?
raise NotImplementedError
@staticmethod
def _getDynamicModuleNamespace():
return 'erp5.component.module'
@staticmethod
def getIdPrefix():
return 'module'
......@@ -27,15 +27,15 @@
#
##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from Products.ERP5Type.Core.ModuleComponent import ModuleComponent
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
import zope.interface
from Products.ERP5Type.interfaces.component import IComponent
class TestComponent(ComponentMixin, TextContentHistoryMixin):
class TestComponent(ModuleComponent):
"""
ZODB Component for Live Tests only (previously defined in the bt5 and
installed in INSTANCE_HOME/tests) as other kind of Tests should be
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from Products.ERP5Type.Core.DocumentComponent import DocumentComponent
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
import zope.interface
from Products.ERP5Type.interfaces.component import IComponent
from Products.CMFCore import utils
class ToolComponent(DocumentComponent):
"""
ZODB Component for Tools, used to be found on Products.XXX.Tool on FS
"""
meta_type = 'ERP5 Tool Component'
portal_type = 'Tool Component'
zope.interface.implements(IComponent)
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
def _hookAfterLoad(self, module_obj):
"""
Register Tool so that it can be added in ZMI through manage_addToolForm.
For FS Tools, this is done during Product initialize() by
Products.CMFCore.utils.ToolInit.
"""
tool_class = getattr(module_obj, self.getReference())
# Should we really use ERP5 Product and not ERP5Type considering that ERP5
# may be gone at some point? Or the other way around? For now, all tools
# have meta_type='ERP5 ...' so just use ERP5 Product.
import Products.ERP5
toolinit = Products.ERP5.__FactoryDispatcher__.toolinit
# Products.CMFCore.utils.ToolInit.initialize()
tool_class.__factory_meta_type__ = toolinit.meta_type
tool_class.icon = 'misc_/%s/%s' % ('ERP5', toolinit.icon)
toolinit.tools.add(tool_class)
@staticmethod
def _getFilesystemPath():
# TODO-arnau: useful?
raise NotImplementedError
@staticmethod
def _getDynamicModuleNamespace():
return 'erp5.component.tool'
@staticmethod
def getIdPrefix():
return 'tool'
......@@ -61,7 +61,9 @@ class PropertySheetTool(BaseTool):
_bootstrap_business_template_property_tuple = (
'template_catalog_security_uid_column_property',
'template_interface_id_property',
'template_mixin_id_property')
'template_mixin_id_property',
'template_module_component_id_property',
'template_tool_component_id_property')
def _isBootstrapRequired(self):
if not self.has_key('BaseType'):
......
......@@ -257,7 +257,8 @@ class TypesTool(TypeProvider):
Documents) that can be used as Base classes
"""
from Products.ERP5Type import document_class_registry
return self._getTypeList('Document Component', document_class_registry)
return self._getTypeList(('Document Component', 'Tool Component'),
document_class_registry)
security.declareProtected(Permissions.AccessContentsInformation, 'getMixinTypeList')
def getMixinTypeList(self):
......
......@@ -1168,13 +1168,13 @@ def initializeProduct( context,
registerDocumentClass(tool.__module__, tool.__name__)
try:
utils.ToolInit('%s Tool' % product_name,
tools=tools,
tools=set(tools),
icon='tool.png',
).initialize( context )
except TypeError:
# product_name parameter is deprecated in CMF
utils.ToolInit('%s Tool' % product_name,
tools=tools,
tools=set(tools),
product_name=product_name,
icon='tool.png',
).initialize( context )
......
......@@ -318,10 +318,12 @@ class ComponentDynamicPackage(ModuleType):
import erp5.component
erp5.component.ref_manager.add_module(module)
return module
finally:
imp.release_lock()
component._hookAfterLoad(module)
return module
def load_module(self, fullname):
"""
Make sure that loading module is thread-safe using aq_method_lock to make
......@@ -411,3 +413,18 @@ class ComponentDynamicPackage(ModuleType):
del sys.modules[module_name]
delattr(package, name)
class ToolComponentDynamicPackage(ComponentDynamicPackage):
def reset(self, *args, **kw):
"""
Reset CMFCore list of Tools (manage_addToolForm)
"""
import Products.ERP5
toolinit = Products.ERP5.__FactoryDispatcher__.toolinit
reset_tool_set = set()
for tool in toolinit.tools:
if not tool.__module__.startswith(self._namespace_prefix):
reset_tool_set.add(tool)
toolinit.tools = reset_tool_set
super(ToolComponentDynamicPackage, self).reset(*args, **kw)
......@@ -180,12 +180,16 @@ def initializeDynamicModules():
holds accessors holders of Portal Types
erp5.component:
holds ZODB Component packages
erp5.component.module:
holds Module (eg any module not being one of the following and used to be found in Products.NAME on FS)
erp5.component.document:
holds Document modules previously found in bt5 in $INSTANCE_HOME/Document
erp5.component.interface:
holds Interface modules previously found in Products.NAME.interfaces
erp5.component.mixin:
holds Mixin modules previously found in Products.NAME.mixin
erp5.component.Tool:
holds Tool modules previously found in Products.NAME.Tool
erp5.component.extension:
holds Extension modules previously found in bt5 in
$INSTANCE_HOME/Extensions
......@@ -221,7 +225,8 @@ def initializeDynamicModules():
# ZODB Components
erp5.component = ComponentPackageType("erp5.component")
from component_package import ComponentDynamicPackage
from component_package import (ComponentDynamicPackage,
ToolComponentDynamicPackage)
# Prevent other threads to create erp5.* packages and modules or seeing them
# incompletely
......@@ -234,12 +239,18 @@ def initializeDynamicModules():
erp5.accessor_holder.property_sheet
sys.modules["erp5.component"] = erp5.component
erp5.component.module = ComponentDynamicPackage('erp5.component.module',
'Module Component')
erp5.component.extension = ComponentDynamicPackage('erp5.component.extension',
'Extension Component')
erp5.component.document = ComponentDynamicPackage('erp5.component.document',
'Document Component')
erp5.component.tool = ToolComponentDynamicPackage('erp5.component.tool',
'Tool Component')
erp5.component.interface = ComponentDynamicPackage('erp5.component.interface',
'Interface Component')
......
......@@ -212,8 +212,16 @@ def generatePortalTypeClass(site, portal_type_name):
type_class_namespace = document_class_registry.get(type_class, '')
if not (type_class_namespace.startswith('Products.ERP5Type') or
portal_type_name in core_portal_type_class_dict):
import erp5.component.document
module = erp5.component.document.find_load_module(type_class)
module = None
if portal_type_name.endswith('Tool'):
import erp5.component.tool
module = erp5.component.tool.find_load_module(type_class)
# Tool Component was introduced recently and some Tool have already been
# migrated as Document Component
if module is None:
import erp5.component.document
module = erp5.component.document.find_load_module(type_class)
if module is not None:
try:
klass = getattr(module, type_class)
......@@ -230,7 +238,14 @@ def generatePortalTypeClass(site, portal_type_name):
% (type_class, portal_type_name))
if klass is None:
klass = _importClass(type_class_path)
try:
klass = _importClass(type_class_path)
except ImportError:
error_msg = 'Could not import %s of Portal Type %s' % (type_class,
portal_type_name)
LOG("ERP5Type.Dynamic", WARNING, error_msg, error=True)
raise AttributeError(error_msg)
global property_sheet_generating_portal_type_set
......
......@@ -36,6 +36,12 @@ class IComponent(Interface):
Extensions or Documents, or any interfaces, mixin and Documents from
Products. Any Component class must implement this interface
"""
def _hookAfterLoad(self, module_obj):
"""
Idempotent hook called after loading the module
"""
pass
def checkConsistency(obj, *args, **kwargs):
"""
Check the consistency of a ZODB Component when validating from draft state
......@@ -68,7 +74,12 @@ class IComponent(Interface):
Return the ID prefix for Component objects
"""
def importFromFilesystem(cls, context, reference, version, source_reference=None):
def importFromFilesystem(cls,
context,
reference,
version,
source_reference=None,
filesystem_zodb_module_mapping_set=None):
"""
Import a Component from the filesystem into ZODB after checking that the
source code is valid
......
......@@ -193,6 +193,9 @@ class ComponentMixin(PropertyRecordableMixin, Base):
_message_text_content_not_set = "No source code"
_message_text_content_error = "Error in Source Code: ${error_message}"
def _hookAfterLoad(self, module_obj):
pass
security.declareProtected(Permissions.AccessContentsInformation,
'getValidationState')
def getValidationState(self):
......@@ -352,7 +355,12 @@ class ComponentMixin(PropertyRecordableMixin, Base):
security.declareProtected(Permissions.ModifyPortalContent,
'importFromFilesystem')
@classmethod
def importFromFilesystem(cls, context, reference, version, source_reference=None):
def importFromFilesystem(cls,
context,
reference,
version,
source_reference=None,
filesystem_zodb_module_mapping_set=None):
"""
Import a Component from the filesystem into ZODB and validate it so it can
be loaded straightaway provided validate() does not raise any error of
......@@ -368,7 +376,20 @@ class ComponentMixin(PropertyRecordableMixin, Base):
path = inspect.getsourcefile(module_obj)
with open(path) as f:
source_code = f.read()
if filesystem_zodb_module_mapping_set is None:
source_code = f.read()
else:
source_code_line_list = []
for line in f:
for (filesystem_module,
zodb_module) in filesystem_zodb_module_mapping_set:
if line.startswith("from " + filesystem_module):
line = line.replace(filesystem_module, zodb_module, 1)
break
source_code_line_list.append(line)
source_code = ''.join(source_code_line_list)
# Checking that the source code is syntactically correct is not
# needed when importing from filesystem, moreover errors may occur
......
......@@ -65,3 +65,37 @@ def _setCacheHeaders(obj, extra_context):
import Products.CMFCore.utils
Products.CMFCore.utils._setCacheHeaders = _setCacheHeaders
# To load all erp5.component.tool.* so that they can be added through 'ERP5
# Site' => Add 'ERP5 Tool'.
from Products.CMFCore.utils import addInstanceForm
def manage_addToolForm(self, REQUEST):
""" Show the add tool form.
"""
from Products.ERP5.ERP5Site import getSite
import erp5.component.tool
seen_tool_component_set = set()
for tool_component in getSite().portal_components.objectValues(portal_type='Tool Component'):
if tool_component.getValidationState() == 'validated':
module_name = tool_component.getReference()
# In case there are several versions, only load the 'default' one
if module_name not in seen_tool_component_set:
erp5.component.tool.find_load_module(module_name)
seen_tool_component_set.add(module_name)
# self is a FactoryDispatcher.
toolinit = self.toolinit
tl = []
for tool in toolinit.tools:
tl.append(tool.meta_type)
return addInstanceForm(addInstanceForm, self, REQUEST,
factory_action='manage_addTool',
factory_meta_type=toolinit.meta_type,
factory_product_name=toolinit.product_name,
factory_icon=toolinit.icon,
factory_types_list=tl,
factory_need_id=0)
Products.CMFCore.utils.manage_addToolForm = manage_addToolForm
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