Commit 7d897440 authored by Ayush Tiwari's avatar Ayush Tiwari

erp5_catalog: Dynamic migration of ZMI catalog to ERP5-ified catalog

And, Patch changeObjectClass extension to remove useless attributes

Copying __dict__ from one object to another brings us to situation where
we don't have many objects which we don't need at all, for example, migrating
objects with subclasses who were initially OFS objects and later an ERP5
object can lead to adding subobjects as attributes of the new object, which
is completely undesirable. To handle this, it is important to delete the
sub-objects as the attributes for those migrated classes.

Old Catalog Tool didn't have portal_type attribute, so while migrating
via synchronizeDynamicModule, after _bootstrap, we expect the tool to
have a portal_type to finalize migration.

This step is now being done only at the end of _bootstrap after we
change the classes for portal_catalog and its sub-objects.
parent 064d305a
...@@ -1748,8 +1748,8 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin): ...@@ -1748,8 +1748,8 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
tool = tool.activate() tool = tool.activate()
tool.migrateToPortalTypeClass(tool_id not in ( tool.migrateToPortalTypeClass(tool_id not in (
'portal_activities', 'portal_simulation', 'portal_templates', 'portal_activities', 'portal_simulation', 'portal_templates',
'portal_trash')) 'portal_trash', 'portal_catalog'))
if tool_id in ('portal_trash',): if tool_id in ('portal_trash', 'portal_catalog'):
for obj in tool.objectValues(): for obj in tool.objectValues():
obj.migrateToPortalTypeClass() obj.migrateToPortalTypeClass()
......
...@@ -24,6 +24,19 @@ def changeObjectClass(self, object_id, new_class): ...@@ -24,6 +24,19 @@ def changeObjectClass(self, object_id, new_class):
new_obj.__dict__.update(old_obj.__dict__) new_obj.__dict__.update(old_obj.__dict__)
if new_class.__module__ == 'erp5.portal_type': if new_class.__module__ == 'erp5.portal_type':
new_obj.portal_type = new_class.__name__ new_obj.portal_type = new_class.__name__
# Workaround for new object which inherit from Folder or XMLobject
# For the CMF objects, the sub-objects acts as attributes, but for the objects
# inside they should be inside the HBTree to be called subobject.
# This patch adds the objects as sub-objects for those erp5 objects
if new_obj._getOb.__module__ == 'Products.ERP5Type.Core.Folder':
for obj in old_obj.objectValues():
# We don't want to keep the sub-objects as attributes for any objects
# specifically for objects which we are shifting to dynamic portal_type
# classes, cause if we edit or delete object, it would only delete the
# object and not remove the attribute, which leads to error if we try
# adding object with same id.
delattr(new_obj, obj.id)
new_obj._setOb(obj.id, obj)
self._setOb(object_id, new_obj) self._setOb(object_id, new_obj)
if self._delOb.__module__ == 'OFS.ObjectManager': if self._delOb.__module__ == 'OFS.ObjectManager':
# Workaround OFS updating '_objects' in _[ds]etObject instead of _[ds]etOb # Workaround OFS updating '_objects' in _[ds]etObject instead of _[ds]etOb
...@@ -34,6 +47,10 @@ def changeObjectClass(self, object_id, new_class): ...@@ -34,6 +47,10 @@ def changeObjectClass(self, object_id, new_class):
new_obj = self._getOb(object_id, new_obj) new_obj = self._getOb(object_id, new_obj)
if new_obj.isIndexable: if new_obj.isIndexable:
new_obj.reindexObject() new_obj.reindexObject()
elif new_obj.portal_type == 'Catalog':
# In case of 'Catalog' portal_type, we don't want unindexing or reindexing
# as we don't expect it to be indexable.
pass
else: else:
old_obj.unindexObject() old_obj.unindexObject()
return new_obj return new_obj
......
...@@ -361,6 +361,79 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -361,6 +361,79 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
, 'manage_schema') , 'manage_schema')
manage_schema = DTMLFile('dtml/manageSchema', globals()) manage_schema = DTMLFile('dtml/manageSchema', globals())
def _isBootstrapRequired(self):
return True
def _bootstrap(self):
# Get erp5 site
parent = self.aq_parent
portal_types = parent.portal_types
portal_property_sheets = parent.portal_property_sheets
from Products.ERP5.ERP5Site import ERP5Generator
ERP5Generator.bootstrap(portal_types, 'erp5_core', 'PortalTypeTemplateItem', (
'Catalog',
'Catalog Tool',
'SQL Method',
'Python Script'
))
ERP5Generator.bootstrap(portal_property_sheets, 'erp5_core', 'PropertySheetTemplateItem', (
'Catalog',
'CatalogTool',
'SQLMethod',
'PythonScript',
'CatalogFilter'
))
# We need ERP5 Form portal_type to exist during migration we would be
# indexing some ERP5 Form objects.
ERP5Generator.bootstrap(portal_types, 'erp5_hal_json_style', 'PortalTypeTemplateItem', (
'ERP5 Form',
))
import erp5
from Products.ERP5.Extensions.CheckPortalTypes import changeObjectClass
# Get all dynamic classes from portal_type
catalog_tool_class = getattr(erp5.portal_type, 'Catalog Tool')
catalog_class = getattr(erp5.portal_type, 'Catalog')
sql_class = getattr(erp5.portal_type, 'SQL Method')
script_class = getattr(erp5.portal_type, 'Python Script')
if not catalog_tool_class:
LOG('OldCatalogTool', WARNING, "Portal Type Catalog Tool doesn't exist")
return
# Change classes for all object inside catalog and catalog_tool
for obj in self.objectValues():
filter_dict = obj.filter_dict
for method in obj.objectValues():
if method.meta_type == 'Z SQL Method':
new_method = changeObjectClass(obj, method.id, sql_class)
elif method.meta_type == 'Script (Python)':
new_method = changeObjectClass(obj, method.id, script_class)
else:
LOG('Catalog Migration', WARNING, '''Subobject %s is not of meta_type \
Z SQL Method or Script(Python)'''%method.id)
return
# Migrate filter_dict and keep them as properties for the methods
new_method_id = new_method.id
if new_method_id in filter_dict:
filter_ = filter_dict[new_method_id]
new_method.setFiltered(filter_['filtered'])
new_method.setTypeList(filter_['type'])
new_method.setExpressionCacheKeyList(filter_['expression_cache_key'])
new_method.setExpression(filter_['expression'])
new_method.setExpressionInstance(filter_['expression_instance'])
# Delete filter_dict before migration of catalog object(s)
del obj.filter_dict
changeObjectClass(self, obj.id, catalog_class)
changeObjectClass(parent, self.id, catalog_tool_class)
# Update some required attributes to the portal_catalog object
parent.portal_catalog.default_erp5_catalog_id = self.default_sql_catalog_id
del parent.portal_catalog.default_sql_catalog_id
security.declarePublic('getPreferredSQLCatalogId') security.declarePublic('getPreferredSQLCatalogId')
def getPreferredSQLCatalogId(self, id=None): def getPreferredSQLCatalogId(self, id=None):
""" """
......
...@@ -327,14 +327,25 @@ def synchronizeDynamicModules(context, force=False): ...@@ -327,14 +327,25 @@ def synchronizeDynamicModules(context, force=False):
from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool
from Products.ERP5Type.Tool.TypesTool import TypesTool from Products.ERP5Type.Tool.TypesTool import TypesTool
from Products.ERP5Type.Tool.ComponentTool import ComponentTool from Products.ERP5Type.Tool.ComponentTool import ComponentTool
from Products.ERP5Catalog.Tool.ERP5CatalogTool import ERP5CatalogTool
try: try:
for tool_class in TypesTool, PropertySheetTool, ComponentTool: for tool_class in TypesTool, PropertySheetTool, ComponentTool, ERP5CatalogTool:
# if the instance has no property sheet tool, or incomplete # if the instance has no property sheet tool, or incomplete
# property sheets, we need to import some data to bootstrap # property sheets, we need to import some data to bootstrap
# (only likely to happen on the first run ever) # (only likely to happen on the first run ever)
tool_id = tool_class.id tool_id = tool_class.id
tool = getattr(portal, tool_id, None) tool = getattr(portal, tool_id, None)
if tool is None: if tool is None:
if tool_class == ERP5CatalogTool:
# Wait till we find that SQL Catalog Tool is installed
# Simpy said, we don't want ERP5 Catalog Tool to be installed
# from here. So, we come to 2 cases:
# 1. Running ERP5Site with sql catalog_tool : In that case, we end up
# running _bootstrap from here, leading to migration.
# 2. New ERP5Site : In this case, we don't do anything here, cause
# the catalog_tool would be ERP5CatalogTool, so this would just pass.
continue
tool = tool_class() tool = tool_class()
portal._setObject(tool_id, tool, set_owner=False, portal._setObject(tool_id, tool, set_owner=False,
suppress_events=True) suppress_events=True)
......
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