diff --git a/Products/CMFPlone/patches/__init__.py b/Products/CMFPlone/patches/__init__.py index e8234dc395..1ad897edc1 100644 --- a/Products/CMFPlone/patches/__init__.py +++ b/Products/CMFPlone/patches/__init__.py @@ -30,6 +30,6 @@ from . import publishing from . import templatecookcheck # Make sure templates aren't re-read in from . import z3c_form - +from . import cmfcatalogaware # production sites diff --git a/Products/CMFPlone/patches/cmfcatalogaware.py b/Products/CMFPlone/patches/cmfcatalogaware.py new file mode 100644 index 0000000000..5b81ef1390 --- /dev/null +++ b/Products/CMFPlone/patches/cmfcatalogaware.py @@ -0,0 +1,89 @@ +import inspect +from Acquisition import aq_base +from OFS.interfaces import IObjectWillBeMovedEvent +from Products.CMFCore.CMFCatalogAware import handleContentishEvent as orig +from Products.CMFCore.indexing import getQueue +from Products.CMFCore.interfaces import ICatalogTool +from zope.container.interfaces import IObjectAddedEvent +from zope.container.interfaces import IObjectMovedEvent +from zope.lifecycleevent.interfaces import IObjectCopiedEvent +from zope.lifecycleevent.interfaces import IObjectCreatedEvent +from zope.component import queryUtility +from zope.component import ComponentLookupError + + +def handleContentishEvent(ob, event): + """ Event subscriber for (IContentish, IObjectEvent) events. + """ + if IObjectAddedEvent.providedBy(event): + ob.notifyWorkflowCreated() + ob.indexObject() + + elif IObjectWillBeMovedEvent.providedBy(event): + # Move/Rename + if event.oldParent is not None and event.newParent is not None: + try: + catalog = queryUtility(ICatalogTool) + except ComponentLookupError: + # Happens when renaming a Plone Site in the ZMI. + # Then it is best to manually clear and rebuild + # the catalog later anyway. + # But for now do what would happen without our patch. + ob.unindexObject() + else: + ob_path = '/'.join(ob.getPhysicalPath()) + rid = catalog._catalog.uids.get(ob_path) + if rid is not None: + setattr(ob, '__rid', rid) + else: + # This may happen if deferred indexing is active and an + # object is added and renamed/moved in the same transaction + # (e.g. moved in an IObjectAddedEvent handler) + return + elif event.oldParent is not None: + # Delete + ob.unindexObject() + + elif IObjectMovedEvent.providedBy(event): + if event.newParent is not None: + rid = getattr(ob, '__rid', None) + if rid: + catalog = queryUtility(ICatalogTool) + _catalog = catalog._catalog + + new_path = '/'.join(ob.getPhysicalPath()) + old_path = _catalog.paths[rid] + + # Make sure the queue is empty before we update catalog internals + getQueue().process() + + del _catalog.uids[old_path] + _catalog.uids[new_path] = rid + _catalog.paths[rid] = new_path + + ob.reindexObject( + idxs=["allowedRolesAndUsers", "path", "getId", "id"] + ) + + delattr(ob, '__rid') + else: + # This may happen if deferred indexing is active and an + # object is added and renamed/moved in the same transaction + # (e.g. moved in an IObjectAddedEvent handler) + ob.indexObject() + + elif IObjectCopiedEvent.providedBy(event): + if hasattr(aq_base(ob), 'workflow_history'): + del ob.workflow_history + + elif IObjectCreatedEvent.providedBy(event): + if hasattr(aq_base(ob), 'addCreator'): + ob.addCreator() + + +globals = orig.__globals__ +globals.update({"getQueue": getQueue}) +source = "\n" * (handleContentishEvent.__code__.co_firstlineno - 1) + inspect.getsource(handleContentishEvent) +code = compile(source, handleContentishEvent.__code__.co_filename, 'exec') +exec(code, globals) +orig.__code__ = globals["handleContentishEvent"].__code__