From bc0e76efecc46f90898a33f5813276fe28063314 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Thu, 22 Oct 2015 09:59:11 +0200
Subject: [PATCH] preference: more scalable way of disabling other preferences

This relies on selecting preferences using owner= catalog key.
This way also supports the edge case where the user has a "Owner" role defined in acl_users.
---
 .../Preference_disableOtherPreferences.xml    | 89 +++++++++++++++++++
 .../scripts/disableOtherPreferences.xml       | 24 +----
 product/ERP5Form/Document/Preference.py       |  4 +-
 product/ERP5Form/tests/testPreferences.py     |  1 +
 4 files changed, 93 insertions(+), 25 deletions(-)
 create mode 100644 product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Preference_disableOtherPreferences.xml

diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Preference_disableOtherPreferences.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Preference_disableOtherPreferences.xml
new file mode 100644
index 0000000000..55601c0ad4
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Preference_disableOtherPreferences.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_body</string> </key>
+            <value> <string># When validating a user preference, we invalidate other user preferences.\n
+\n
+from Products.ERP5Type.Message import translateString\n
+\n
+portal = context.getPortalObject()\n
+\n
+\n
+if context.getPriority() != 3: # XXX 3 is Priority.USER\n
+  return\n
+\n
+for preference in portal.portal_preferences.searchFolder(\n
+    owner=str(portal.portal_membership.getAuthenticatedMember()),\n
+    portal_type=context.getPortalType()):\n
+  preference = preference.getObject()\n
+  assert portal.portal_membership.getAuthenticatedMember().allowed(preference, [\'Owner\', ]), preference\n
+\n
+  if preference != context and \\\n
+      preference.getPreferenceState() == \'enabled\' and \\\n
+      preference.getPriority() == context.getPriority():\n
+    preference.disable(\n
+      comment=translateString(\n
+        \'Automatically disabled when enabling ${preference_title}.\',\n
+        mapping={\'preference_title\': context.getTitle()}))\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Preference_disableOtherPreferences</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/preference_workflow/scripts/disableOtherPreferences.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/preference_workflow/scripts/disableOtherPreferences.xml
index e89d51c7a5..928b588bcd 100644
--- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/preference_workflow/scripts/disableOtherPreferences.xml
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/preference_workflow/scripts/disableOtherPreferences.xml
@@ -50,29 +50,7 @@
         </item>
         <item>
             <key> <string>_body</string> </key>
-            <value> <string>from Products.ERP5Type.Message import translateString\n
-\n
-pref = sci[\'object\']\n
-portal = sci.getPortal()\n
-LOG = lambda msg: pref.log("PreferenceWorkflow.disableOtherPreferences on %s"%pref, msg)\n
-\n
-# deactivate all other preferences of the same level that the user can view\n
-for p in portal.portal_preferences.searchFolder():\n
-  p = p.getObject()\n
-  try :\n
-    if portal.portal_membership.getAuthenticatedMember().allowed(p, [\'Owner\', ]) :\n
-      if p != pref and \\\n
-         p.getPreferenceState() == \'enabled\' and \\\n
-         p.getPriority() == pref.getPriority() and \\\n
-         p.getPortalType() == pref.getPortalType() :\n
-        p.portal_workflow.doActionFor(p,\n
-           \'disable_action\',\n
-           wf_id=\'preference_workflow\', \n
-           comment=translateString(\n
-          \'Automatically disabled when enabling ${preference_title}.\',\n
-          mapping={\'preference_title\': pref.getTitle()}))\n
-  except \'Unauthorized\', a :\n
-    LOG("not authorized to deactivate %s"%p)\n
+            <value> <string>sci[\'object\'].activate().Preference_disableOtherPreferences()\n
 </string> </value>
         </item>
         <item>
diff --git a/product/ERP5Form/Document/Preference.py b/product/ERP5Form/Document/Preference.py
index c60c206e5a..d9c54ba23f 100644
--- a/product/ERP5Form/Document/Preference.py
+++ b/product/ERP5Form/Document/Preference.py
@@ -86,10 +86,10 @@ class Preference( Folder ):
     self._clearCache()
     Folder._edit(self, **kw)
 
-  def enable(self):
+  def enable(self, **kw):
     """Workflow method"""
     self._clearCache()
 
-  def disable(self):
+  def disable(self, **kw):
     """Workflow method"""
     self._clearCache()
diff --git a/product/ERP5Form/tests/testPreferences.py b/product/ERP5Form/tests/testPreferences.py
index c2c9ae0332..c976cb4752 100644
--- a/product/ERP5Form/tests/testPreferences.py
+++ b/product/ERP5Form/tests/testPreferences.py
@@ -153,6 +153,7 @@ class TestPreferences(PropertySheetTestCase):
     self.assertEqual(None,
         self.getPreferenceTool().getActiveSystemPreference())
     self.assertEqual(person2.getPreferenceState(), 'enabled')
+    self.tic()
     # enabling a preference disable all other of the same level
     self.assertEqual(person1.getPreferenceState(), 'disabled')
     self.assertEqual(group.getPreferenceState(),   'enabled')
-- 
2.30.9