Commit 3a6e9d3b authored by iv's avatar iv

ERP5Workflow: use patched version of updateRoleMappingsFor

and improve its performance by avoiding multiple calls to ac_inherited_permissions
by calling multiple times modifyRolesForPermission, by passing a dict as parameter
parent 700675ee
...@@ -31,6 +31,7 @@ import sys ...@@ -31,6 +31,7 @@ import sys
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from AccessControl.unauthorized import Unauthorized from AccessControl.unauthorized import Unauthorized
from AccessControl.Permission import Permission
from AccessControl.SecurityManagement import getSecurityManager from AccessControl.SecurityManagement import getSecurityManager
from Acquisition import aq_base, aq_inner, aq_parent from Acquisition import aq_base, aq_inner, aq_parent
from copy import deepcopy from copy import deepcopy
...@@ -44,8 +45,7 @@ from Products.CMFCore.WorkflowCore import WorkflowException, ObjectDeleted,\ ...@@ -44,8 +45,7 @@ from Products.CMFCore.WorkflowCore import WorkflowException, ObjectDeleted,\
ObjectMoved ObjectMoved
from Products.DCWorkflow.DCWorkflow import ValidationFailed from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.DCWorkflow.Expression import StateChangeInfo from Products.DCWorkflow.Expression import StateChangeInfo
from Products.DCWorkflow.utils import Message as _ from Products.DCWorkflow.utils import ac_inherited_permissions, Message as _
from Products.DCWorkflow.utils import modifyRolesForPermission
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
from Products.ERP5Type.Globals import PersistentMapping from Products.ERP5Type.Globals import PersistentMapping
...@@ -65,6 +65,38 @@ from zLOG import LOG, INFO, WARNING ...@@ -65,6 +65,38 @@ from zLOG import LOG, INFO, WARNING
ACTIVITY_GROUPING_COUNT = 100 ACTIVITY_GROUPING_COUNT = 100
def modifyRolesForPermissionDict(ob, new_permission_roles_dict):
# copied and modified version of modifyRolesForPermission
# in Products.DCWorkflow.utils
# this has been refactored to pass a dict as parameter
# and avoid multiple expensive calls to ac_inherited_permissions
'''
Modifies multiple role to permission mappings. roles is a list to
acquire, a tuple to not acquire.
'''
# This mimics what AccessControl/Role.py does.
new_permission_roles_dict_length = len(new_permission_roles_dict)
modified_dict = {}
for permission in ac_inherited_permissions(ob, 1):
name, value = permission[:2]
if name in new_permission_roles_dict:
p = Permission(name, value, ob)
new_roles = new_permission_roles_dict[name]
if p.getRoles() != new_roles:
p.setRoles(new_roles)
modified_dict[name] = True
else:
modified_dict[name] = False
# once modified_dict is fulled with according permissions, there is no
# need to continue to loop over all possible permissions
if len(modified_dict) == new_permission_roles_dict_length:
break
return modified_dict
class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
""" """
A ERP5 Workflow. A ERP5 Workflow.
...@@ -214,25 +246,65 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -214,25 +246,65 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
return transition return transition
security.declarePrivate('updateRoleMappingsFor') security.declarePrivate('updateRoleMappingsFor')
def updateRoleMappingsFor(self, document): def updateRoleMappingsFor(self, ob):
""" # Patch updateRoleMappingsFor so that if 2 workflows define security, then
Changes the object permissions according to the current state. # we should do an AND operation between each permission
""" '''
Changes the object permissions according to the current
state.
'''
changed = False changed = False
state = self._getWorkflowStateOf(document, id_only=False) state = self._getWorkflowStateOf(ob)
if state is not None:
state_permission_list = state.getAcquirePermissionList() tool = aq_parent(aq_inner(self))
for permission, role_list in state.getStatePermissionRolesDict().items(): other_workflow_list = [x for x in tool.getWorkflowsFor(ob)
# tuple means "don't acquire" in zope internal security and list if x.id != self.id and x.getPortalType() in
# is used when acquisition should be done ('DCWorkflowDefinition', 'Workflow')]
if permission in state_permission_list: other_data_list = []
role_list = list(role_list) new_permission_roles_dict = {}
else:
role_list = tuple(role_list) for other_workflow in other_workflow_list:
if modifyRolesForPermission(document, permission, role_list): other_state = other_workflow._getWorkflowStateOf(ob)
if other_state is not None:
other_state_permission_roles_dict = other_state.getStatePermissionRolesDict()
if other_state_permission_roles_dict is not None:
other_data_list.append((other_workflow,other_state))
# Be carefull, permissions_roles should not change
# from list to tuple or vice-versa. (in modifyRolesForPermission,
# list means acquire roles, tuple means do not acquire)
if state is not None and self.workflow_managed_permission:
for p in self.workflow_managed_permission:
roles = []
refused_roles = []
other_role_type_list = []
state_permission_roles_dict = state.getStatePermissionRolesDict()
if state_permission_roles_dict is not None:
roles = state_permission_roles_dict.get(p, roles)
role_type = type(roles)
roles = list(roles)
# We will check that each role is activated
# in each DCWorkflow
for other_workflow, other_state in other_data_list:
if p in other_workflow.workflow_managed_permission:
other_roles = other_state.getStatePermissionRolesDict().get(p, [])
other_role_type_list.append(type(other_roles))
for role in roles:
if role not in other_roles:
refused_roles.append(role)
for role in refused_roles:
if role in roles:
roles.remove(role)
if role_type is tuple and ((not other_role_type_list) or
(list not in other_role_type_list)):
# If at least, one of other workflows manage security and for all
# are role_type are tuple
roles = tuple(roles)
new_permission_roles_dict[p] = roles
if True in modifyRolesForPermissionDict(ob, new_permission_roles_dict).values():
changed = True changed = True
return changed return changed
# This method allows to update all objects using one workflow, for example # This method allows to update all objects using one workflow, for example
# after the permissions per state for this workflow were modified # after the permissions per state for this workflow were modified
def updateRoleMappings(self, REQUEST=None): def updateRoleMappings(self, REQUEST=None):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment