From 93bd0efeb1ba3c71f2b44c1f5d93b134dd566cf9 Mon Sep 17 00:00:00 2001
From: Sebastien Robin <seb@nexedi.com>
Date: Thu, 21 Jun 2007 15:48:59 +0000
Subject: [PATCH] - added method callMethodOnObjectList on Folder - Make the
 updateRoleMapping method on RoleProviderBase much more   scallable. It will
 easily works with thousands of objects, but   probably not enough for
 millions

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14916 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Type/Core/Folder.py      | 17 +++++++++++++++++
 product/ERP5Type/RoleProviderBase.py | 27 ++++++++++++++++-----------
 2 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/product/ERP5Type/Core/Folder.py b/product/ERP5Type/Core/Folder.py
index 5e42d7b93f..19ed7ffda1 100644
--- a/product/ERP5Type/Core/Folder.py
+++ b/product/ERP5Type/Core/Folder.py
@@ -33,6 +33,7 @@ import ExtensionClass
 
 from Products.CMFCore.utils import _getAuthenticatedUser
 from Products.CMFCore.CMFCatalogAware import CMFCatalogAware
+from Products.CMFCore import CMFCorePermissions
 
 from Products.ERP5Type.Base import Base
 from Products.ERP5Type.CopySupport import CopyContainer
@@ -932,5 +933,21 @@ class Folder( CopyContainer, CMFBTreeFolder, Base, FolderMixIn):
     object.manage_beforeDelete(object, self)
     self._delOb(id)
 
+  security.declareProtected( CMFCorePermissions.ManagePortal, 'callMethodOnObjectList' )
+  def callMethodOnObjectList(self, object_path_list, method_id, *args, **kw):
+    """
+    Very usefull if we want to activate the call of a method
+    on many objects at a time. Like this we could prevent creating
+    too much acitivities at a time, and we may have only the path
+
+    """
+    portal = self.getPortalObject()
+    for object_path in object_path_list:
+      current_object = portal.unrestrictedTraverse(object_path)
+      method = getattr(current_object, method_id, None)
+      if method is None:
+        raise ValueError, "The method %s was not found" % method_id
+      method(*args, **kw)
+
 # Overwrite Zope setTitle()
 Folder.setTitle = Base.setTitle
diff --git a/product/ERP5Type/RoleProviderBase.py b/product/ERP5Type/RoleProviderBase.py
index 73ee3e9f66..5658a25c46 100644
--- a/product/ERP5Type/RoleProviderBase.py
+++ b/product/ERP5Type/RoleProviderBase.py
@@ -23,6 +23,8 @@ from Products.ERP5Type import _dtmldir
 from RoleInformation import RoleInformation
 from Permissions import ManagePortal
 
+from zLOG import LOG
+
 #from interfaces.portal_roles import RoleProvider as IRoleProvider
 
 
@@ -257,18 +259,21 @@ class RoleProviderBase:
       """Update the local roles in existing objects.
       """
       portal_catalog = self.portal_catalog
-      i = 0
-      for brain in portal_catalog(portal_type = self.id):
-        obj = brain.getObject()
-        user_id = None
-        owner_tuple = obj.getOwnerTuple()
-        if owner_tuple is not None:
-          user_id = owner_tuple[1]
-        obj.updateLocalRolesOnSecurityGroups(user_name = user_id)
-        i += 1
 
-      if REQUEST is not None:
-        return self.manage_editRolesForm(REQUEST, manage_tabs_message='%d objects updated' % (i,))
+      object_list = portal_catalog(portal_type = self.id, limit=None)
+      # We need to use activities in order to make sure it will
+      # work for an important number of objects
+      object_list_len = len(object_list)
+      portal_activities = self.portal_activities
+      object_path_list = [x.path for x in object_list]
+      for i in xrange(0, object_list_len, 100):
+        current_path_list = object_path_list[i:i+100]
+        portal_activities.activate(activity='SQLQueue')\
+              .callMethodOnObjectList(current_path_list, 
+                     'updateLocalRolesOnSecurityGroups')
 
+      if REQUEST is not None:
+        return self.manage_editRolesForm(REQUEST, 
+                 manage_tabs_message='%d objects updated' % (object_list_len,))
 
 InitializeClass(RoleProviderBase)
-- 
2.30.9