From a28cf296be5db64ff1c9c91cae7b6ba7106c50d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Mon, 18 Mar 2013 10:33:48 +0100
Subject: [PATCH] Rework LocalRolesTemplateItem with local role group ids.

We were not able to export and import back roles of a document when more than
one local role group id was used.
---
 product/ERP5/Document/BusinessTemplate.py     | 29 ++++++++-------
 product/ERP5/tests/testBusinessTemplate.py    | 36 ++++++++++++++-----
 .../testERP5CatalogSecurityUidOptimization.py |  1 -
 3 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/product/ERP5/Document/BusinessTemplate.py b/product/ERP5/Document/BusinessTemplate.py
index 565a208b18..13695c213d 100644
--- a/product/ERP5/Document/BusinessTemplate.py
+++ b/product/ERP5/Document/BusinessTemplate.py
@@ -4568,15 +4568,14 @@ class LocalRolesTemplateItem(BaseTemplateItem):
     if local_roles_group_id_dict:
       # local roles group id dict (not included by default to be stable with
       # old bts)
-      xml_data += '\n <local_roles_group_id>'
-      for principal, local_roles_group_id_list in sorted(local_roles_group_id_dict.items()):
-        xml_data += "\n  <principal id='%s'>" % escape(principal)
-        for local_roles_group_id in local_roles_group_id_list:
-          for item in local_roles_group_id:
-            xml_data += "\n    <local_roles_group_id>%s</local_roles_group_id>" % \
-                escape(item)
-        xml_data += "\n  </principal>"
-      xml_data += '\n </local_roles_group_id>'
+      xml_data += '\n <local_role_group_ids>'
+      for local_role_group_id, local_roles_group_id_list in sorted(local_roles_group_id_dict.items()):
+        xml_data += "\n  <local_role_group_id id='%s'>" % escape(local_role_group_id)
+        for principal, role in sorted(local_roles_group_id_list):
+          xml_data += "\n    <principal id='%s'>%s</principal>" % \
+                (escape(principal), escape(role))
+        xml_data += "\n  </local_role_group_id>"
+      xml_data += '\n </local_role_group_ids>'
 
     xml_data += '\n</local_roles_item>'
     if isinstance(xml_data, unicode):
@@ -4605,10 +4604,11 @@ class LocalRolesTemplateItem(BaseTemplateItem):
 
     # local roles group id
     local_roles_group_id_dict = {}
-    for principal in xml.findall('//principal'):
-      local_roles_group_id_dict[principal.get('id')] = set([tuple(
-        [group_id.text for group_id in
-            principal.findall('./local_roles_group_id')])])
+    for local_role_group_id in xml.findall('//local_role_group_id'):
+      role_set = set()
+      for principal in local_role_group_id.findall('./principal'):
+        role_set.add((principal.get('id'), principal.text))
+      local_roles_group_id_dict[local_role_group_id.get('id')] = role_set
     self._objects['local_roles/%s' % (file_name[:-4],)] = (
       local_roles_dict, local_roles_group_id_dict)
 
@@ -4655,6 +4655,9 @@ class LocalRolesTemplateItem(BaseTemplateItem):
       obj = p.unrestrictedTraverse(path, None)
       if obj is not None:
         setattr(obj, '__ac_local_roles__', {})
+        if getattr(aq_base(obj), '__ac_local_roles_group_id_dict__',
+                    None) is not None:
+          delattr(obj, '__ac_local_roles_group_id_dict__')
         obj.reindexObject()
 
 class BusinessTemplate(XMLObject):
diff --git a/product/ERP5/tests/testBusinessTemplate.py b/product/ERP5/tests/testBusinessTemplate.py
index 41497358f3..cf0f2fd363 100644
--- a/product/ERP5/tests/testBusinessTemplate.py
+++ b/product/ERP5/tests/testBusinessTemplate.py
@@ -6609,12 +6609,17 @@ class TestBusinessTemplate(BusinessTemplateMixin):
     sql_catalog.sql_catalog_security_uid_columns = (
       ' | security_uid',
       'Alternate | alternate_security_uid',
+      'Another | another_security_uid',
     )
-    # add category
+    # add categories
     self.portal.portal_categories.local_role_group.newContent(
-      portal_type='Category', 
-      reference = 'Alternate',
-      id = 'Alternate')
+      portal_type='Category',
+      reference='Alternate',
+      id='Alternate')
+    self.portal.portal_categories.local_role_group.newContent(
+      portal_type='Category',
+      reference='Another',
+      id='Another')
 
     types_tool = self.portal.portal_types
     object_type = types_tool.newContent('Geek Object', 'Base Type',
@@ -6630,11 +6635,18 @@ class TestBusinessTemplate(BusinessTemplateMixin):
       portal_type='Geek Object', id='1')
 
     # simulate role assignment
-    new_object.__ac_local_roles__ = dict(group=['Assignee'])
-    initial___ac_local_roles_group_id_dict__ = dict(Alternate=set([('group', 'Assignee')]))
+    new_object.__ac_local_roles__ = dict(group=['Assignee', 'Assignor'],
+                                         another_group=['Assignee'])
+    initial___ac_local_roles_group_id_dict__ = dict(
+      Alternate=set([('group', 'Assignee')]),
+      Another=set([('group', 'Assignor'),
+                   ('another_group', 'Assignee')])).copy()
     new_object.__ac_local_roles_group_id_dict__ = initial___ac_local_roles_group_id_dict__
     self.tic()
 
+    # the role information defined here does not match the assigned roles that
+    # we simulated above, but we just want to test that an exported role
+    # information can be imported back
     object_type.newContent(portal_type='Role Information',
                            local_role_group_value=self.portal.portal_categories.local_role_group.Alternate.getRelativeUrl(),
                            role_name_list=('Assignee', ))
@@ -6666,13 +6678,19 @@ class TestBusinessTemplate(BusinessTemplateMixin):
     new_bt.install()
     try:
       role, = object_type.getRoleInformationList()
-      self.assertEquals(self.portal.portal_categories.local_role_group.Alternate, 
+      self.assertEquals(self.portal.portal_categories.local_role_group.Alternate,
                         role.getLocalRoleGroupValue())
       path = self.portal.geek_module['1']
-      self.assertEquals([('group', ['Assignee'],)], [item for item in
-            path.__ac_local_roles__.items() if item[1] != ['Owner']])
+      self.assertEquals(sorted([
+        ('another_group', ['Assignee']),
+        ('group', ['Assignee', 'Assignor']),
+        ]), sorted([item for item in
+            path.__ac_local_roles__.items() if item[1] != ['Owner']]))
       self.assertEquals(initial___ac_local_roles_group_id_dict__,
         path.__ac_local_roles_group_id_dict__)
+      # make sure we can reindexing the object works
+      path.recursiveImmediateReindexObject()
+      self.tic()
     finally:
       # restore state
       sql_catalog.sql_catalog_security_uid_columns = \
diff --git a/product/ERP5Catalog/tests/testERP5CatalogSecurityUidOptimization.py b/product/ERP5Catalog/tests/testERP5CatalogSecurityUidOptimization.py
index a4e57d9319..03d7151f88 100644
--- a/product/ERP5Catalog/tests/testERP5CatalogSecurityUidOptimization.py
+++ b/product/ERP5Catalog/tests/testERP5CatalogSecurityUidOptimization.py
@@ -30,7 +30,6 @@
 import unittest
 from Testing import ZopeTestCase
 from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
-from Products.ERP5Type.tests.backportUnittest import expectedFailure
 from AccessControl.SecurityManagement import newSecurityManager
 
 
-- 
2.30.9