import logging from ZODB.loglevels import TRACE from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager from Acquisition import aq_parent from Acquisition import aq_inner from Globals import InitializeClass from Products.CMFCore.utils import getToolByName from Products.CMFCore.WorkflowCore import ObjectMoved from Products.CMFCore.WorkflowCore import ObjectDeleted from Products.CMFCore.WorkflowCore import WorkflowException from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION #from expression import CPSStateChangeInfo as StateChangeInfo #from expression import createExprContext #from zope.interface import implements #from Products.CPSWorkflow.interfaces import ICPSWorkflowDefinition from Products.CPSCore.ProxyBase import ProxyBase from Products.CPSCore.EventServiceTool import getEventService #from constants import TRANSITION_FLAGS_EXPORT # # Backwards compatibility with CPS3 <= 3.2.x # Importing transition flags from here before. # from Products.CPSWorkflow.transitions import * from Products.CPSWorkflow.states import * logger = logging.getLogger('CPSWorkflow.workflow') security = ClassSecurityInfo() security.declarePrivate('updateStackDefinitionsRoleMappingFor') def updateStackDefinitionsRoleMappingsFor(self, ob, **kw): """Update local roles for delegatees that are within workflow stacks """ current_wf_var_id = kw.get('current_wf_var_id', '') wftool = getToolByName(self, 'portal_workflow') stackdefs = wftool.getStackDefinitionsFor(ob) changed = 0 # # First save the former local roles maping They will be # overriden if defined on the state just after. For the other # ones, we need to keep the flrm's since the stackdef might be # defined on another state further within the process # definition or called by a stack flaged transition. # tdef = kw.get('tdef') history = wftool.getHistoryOf(self.id, ob) if history is not None: try: former_status = history[-2] except IndexError: # Virgin instance ;) pass else: sflrm = former_status.get('sflrm', {}) for k, v in sflrm.items(): wftool.updateFormerLocalRoleMappingForStack(ob, self.id, k, v) # # Let's ask the stack definition for the list of local roles # for stackdef in stackdefs.keys(): # Update only the variable on wich the transition just applied if not stackdef == current_wf_var_id: continue ds = wftool.getInfoFor(ob, stackdef, self.id) former_mapping = wftool.getFormerLocalRoleMappingForStack( ob, self.id, stackdef) mapping = stackdefs[stackdef]._getLocalRolesMapping(ds) # # First remove associated local roles to the ones who are not # supposed to have any (not a single one) # for id in former_mapping.keys(): old_local_roles = former_mapping[id] # Remove all previous local roles in this case if id not in mapping.keys(): roles_to_remove = old_local_roles # Remove only local roles that are only within the # previous mapping else: roles_to_remove = [] for old_role in old_local_roles: if old_role not in mapping[id]: roles_to_remove.append(old_role) # Check that no other stack distributes currently this role # to the current member roles_to_keep = () for old_local_role in roles_to_remove: stacks = wftool.getStacks(ob) for stack_id, stack in stacks.items(): if stack_id != current_wf_var_id: # The current transition is already # executed on ob thus we can take the # former mapping for this other given if (old_local_role in wftool.getFormerLocalRoleMappingForStack( ob, self.id, stack_id).get(id, ())): roles_to_keep += (old_local_role,) # Do the actual job to remove absolete roles for old_local_role in roles_to_remove: # Don't remove those already managed by another stack if old_local_role in roles_to_keep: continue if not id.startswith('group:'): current_roles = list( ob.get_local_roles_for_userid(userid=id)) new_roles = [role for role in current_roles if role != old_local_role] ob.manage_delLocalRoles(userids=[id]) if new_roles: ob.manage_setLocalRoles(id, new_roles) else: id = id[len('group:'):] current_roles = list( ob.get_local_roles_for_groupid(groupid=id)) new_roles = [role for role in current_roles if role != old_local_role] ob.manage_delLocalGroupRoles(groupids=[id]) if new_roles: ob.manage_setLocalGroupRoles(id, new_roles) # Update ? if roles_to_remove: changed = 1 # # Add local roles to member / groups within the mapping if # they don't have the roles already in their merged local roles # for id in mapping.keys(): changed = 1 local_roles = mapping[id] if not id.startswith('group:'): current_roles = ob.get_local_roles_for_userid(userid=id) new_roles = list(current_roles) for role in local_roles: if role not in new_roles: new_roles.append(role) ob.manage_setLocalRoles(id, new_roles) else: id = id[len('group:'):] current_roles = ob.get_local_roles_for_groupid(groupid=id) new_roles = list(current_roles) for role in local_roles: if role not in new_roles: new_roles.append(role) ob.manage_setLocalGroupRoles(id, new_roles) # Update the former local role mapping wftool.updateFormerLocalRoleMappingForStack(ob, self.id, stackdef, mapping) return changed from Products.CPSWorkflow.workflow import WorkflowDefinition WorkflowDefinition.updateStackDefinitionsRoleMappingsFor = updateStackDefinitionsRoleMappingsFor