From 8167a837f38d3deff02c5f7853a4ddd2bf979df4 Mon Sep 17 00:00:00 2001
From: Leonardo Rochael Almeida <leonardo@nexedi.com>
Date: Wed, 12 May 2010 18:22:53 +0000
Subject: [PATCH] Automatic migration of actions from non-IActionProviders to
 portal_actions on Zope 2.12

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@35280 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Type/patches/ActionsTool.py | 52 ++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/product/ERP5Type/patches/ActionsTool.py b/product/ERP5Type/patches/ActionsTool.py
index 679e266f9a..7962831502 100644
--- a/product/ERP5Type/patches/ActionsTool.py
+++ b/product/ERP5Type/patches/ActionsTool.py
@@ -12,6 +12,12 @@
 #
 ##############################################################################
 
+import logging
+import transaction
+from Acquisition import aq_parent
+
+logger = logging.getLogger(__name__)
+
 from Products.CMFCore.ActionsTool import ActionsTool
 try:
   from Products.CMFCore.interfaces import IActionProvider
@@ -21,6 +27,36 @@ except ImportError:
   from Products.CMFCore.ActionsTool import IActionProvider
   IActionProvider_providedBy = IActionProvider.isImplementedBy
 
+def migrateNonProviders(portal_actions):
+  portal_actions_path = '/'.join(portal_actions.getPhysicalPath())
+  root = portal_actions.getPhysicalRoot()
+  # Discard all changes so far, we'll restart the request later so no changes
+  # are lost.
+  root._p_jar.sync()
+  txn = transaction.get()
+
+  portal_actions = root.unrestrictedTraverse(portal_actions_path)
+  portal = aq_parent(portal_actions)
+  action_providers = list(portal_actions.action_providers)
+  for provider_name in portal_actions.listActionProviders():
+    provider = getattr(portal, provider_name)
+    if ( getattr(provider, '_actions', ()) and
+         getattr(provider, 'listActionInfos', None) is None ):
+      msg = ('migrating actions from %r to %r' % 
+             (portal_actions_path, '/'.join(provider.getPhysicalPath())))
+      logger.warning(msg)
+      txn.note(msg)
+      portal_actions._actions += provider._actions
+      del provider._actions
+      action_providers.remove(provider_name)
+  portal_actions.action_providers = tuple(action_providers)
+  
+  txn.note('Migrated actions from non IActionProviders to portal_actions')
+  txn.commit()
+  # restart the transaction with actions already migrated
+  from ZODB.POSException import ConflictError
+  raise ConflictError('Action Migration Completed, please restart request.')
+
 ActionsTool_listFilteredActionsFor = ActionsTool.listFilteredActionsFor
 
 def listFilteredActionsFor(self, object=None):
@@ -28,6 +64,13 @@ def listFilteredActionsFor(self, object=None):
 
     This patch removes inclusion of actions from the object itself.
     It was never used and now, it breaks objects inside Types Tool.
+    
+    It also checks for a new ERP5-only actions API (getActionListFor), but
+    this API should be moved to listActionInfos() of each tool so as not to
+    create duplicate code paths that are sources of bugs.
+    
+    Finally, this patch detects tools that are no longer action providers and
+    invokes the migration of their actions to portal_actions 
     """
     actions = []
 
@@ -42,9 +85,16 @@ def listFilteredActionsFor(self, object=None):
                            if action.test(ec))
         elif IActionProvider_providedBy(provider):
             actions.extend( provider.listActionInfos(object=object) )
-        else:
+        elif getattr(provider, '_listActionInfos', None) is not None:
+            # BACK: drop this clause and the 'else' clause below when we
+            # drop CMF 1.5
+
             # for Action Providers written for CMF versions before 1.5
             actions.extend( self._listActionInfos(provider, object) )
+        else:
+            # We're in 2.12 and we need to migrate objects that are no longer
+            # IActionProviders:
+            migrateNonProviders(self)
 
     # Reorganize the actions by category.
     filtered_actions={'user':[],
-- 
2.30.9