def getInfoFor(self, ob, name, default): ''' Allows the user to request information provided by the workflow. This method must perform its own security checks. ''' vdef = getattr(self, name, _MARKER) for r, v in six.iteritems(self.getVariableValueDict()): if r == name: vdef = v break if vdef is _MARKER: return default if not vdef.checkGuard(getSecurityManager(), self, ob): return default status = self._getStatusOf(ob) variable_default_expression = vdef.getVariableDefaultExpression() if status is not None and name in status: value = status[name] # Not set yet. Use a default. elif variable_default_expression is not None: ec = createExpressionContext(StateChangeInfo(ob, self, status)) value = variable_default_expression(ec) else: value = '' return value
def activeScript(self, script_name, ob_url, status, tdef_id): script = self.scripts[script_name] ob = self.unrestrictedTraverse(ob_url) tdef = self.interactions.get(tdef_id) sci = StateChangeInfo( ob, self, status, tdef, None, None, None) script(sci)
def search(self, info=None, **kw): """ Perform the search corresponding to this worklist Returns sequence of ZCatalog brains - info is a mapping for resolving formatted string variable references - additional keyword/value pairs may be used to restrict the query """ if not self.var_matches: return if info is None: info = {} catalog = getToolByName(self, 'portal_catalog') criteria = {} for key, values in self.var_matches.items(): if isinstance(values, Expression): wf = self.getWorkflow() portal = wf._getPortalRoot() context = createExprContext(StateChangeInfo(portal, wf)) criteria[key] = values(context) else: criteria[key] = [x % info for x in values] criteria.update(kw) return catalog.searchResults(**criteria)
def getCatalogVariablesFor(self, ob): ''' Allows this workflow to make workflow-specific variables available to the catalog, making it possible to implement worklists in a simple way. Returns a mapping containing the catalog variables that apply to ob. ''' res = {} status = self._getStatusOf(ob) for id, vdef in self.variables.items(): if vdef.for_catalog: if status.has_key(id): value = status[id] # Not set yet. Use a default. elif vdef.default_expr is not None: ec = createExprContext(StateChangeInfo(ob, self, status)) value = vdef.default_expr(ec) else: value = vdef.default_value res[id] = value # Always provide the state variable. state_var = self.state_var res[state_var] = status.get(state_var, self.initial_state) return res
def notifyBefore(self, ob, transition_list, args=None, kw=None): ''' Notifies this workflow of an action before it happens, allowing veto by exception. Unless an exception is thrown, either a notifySuccess() or notifyException() can be expected later on. The action usually corresponds to a method name. ''' if isinstance(transition_list, basestring): return # Wrap args into kw since this is the only way to be compatible with # DCWorkflow. A better approach consists in extending DCWorkflow if kw is None: kw = {'workflow_method_args' : args} else: kw = kw.copy() kw['workflow_method_args'] = args filtered_transition_list = [] append = filtered_transition_list.append for t_id in transition_list: tdef = self.getTransitionValueByReference(t_id) assert tdef.getTriggerType() == TRIGGER_WORKFLOW_METHOD append(tdef.getId()) former_status = self._getStatusOf(ob) # Pass lots of info to the script in a single parameter. sci = StateChangeInfo(ob, self, former_status, tdef, None, None, kwargs=kw) for script in tdef.getBeforeScriptValueList(): script(sci) # May throw an exception. return filtered_transition_list
def checkGuard(self, security_manager, workflow, current_object, **kw): """ Checks conditions in this guard. Original source code from DCWorkflow (Nexedi patch for proxy_roles) """ user_roles = None def getRoles(): stack = security_manager._context.stack if stack: proxy_roles = getattr(stack[-1], '_proxy_roles', None) if proxy_roles: return proxy_roles return security_manager.getUser().getRolesInContext(current_object) if workflow.isManagerBypass(): # Possibly bypass. user_roles = getRoles() if 'Manager' in user_roles: return True guard_permission_list = self.getGuardPermissionList() if guard_permission_list: for permission in guard_permission_list: if _checkPermission(permission, current_object): break else: return False guard_role_list = self.getGuardRoleList() if guard_role_list: # Require at least one of the given roles. if user_roles is None: user_roles = getRoles() for role in guard_role_list: if role in user_roles: break else: return False guard_group_list = self.getGuardGroupList() if guard_group_list: # Require at least one of the specified groups. user = security_manager.getUser() base = aq_base(user) if hasattr(base, 'getGroupsInContext'): user_groups = user.getGroupsInContext(current_object) elif hasattr(base, 'getGroups'): user_groups = user.getGroups() else: user_groups = () for group in guard_group_list: if group in user_groups: break else: return False guard_expression = self.getGuardExpressionInstance() if guard_expression is not None: return guard_expression( createExpressionContext( StateChangeInfo(current_object, workflow, kwargs=kw))) return True
def callInterationScript(self, script_name, ob, status, tdef_id): self._getOb(script_name)( StateChangeInfo( ob, self, status, self.getTransitionValueByReference(tdef_id), None, None, None, ), )
def callInterationScript(self, script_name, ob, status, tdef_id): self.scripts[script_name](StateChangeInfo( ob, self, status, self.interactions.get(tdef_id), None, None, None, ), )
def execute(self, document, form_kw=None): """ Execute transition. """ workflow = self.getParentValue() # Call the before script _executeBeforeScript(self, document) # Modify the state _changeState(self, document) # Get variable values status_dict = workflow.getCurrentStatusDict(document) status_dict['undo'] = 0 # Modify workflow history state_bc_id = workflow.getStateBaseCategory() state_object = document.unrestrictedTraverse( document.getCategoryMembershipList(state_bc_id)[0]) status_dict[state_bc_id] = state_object.getReference() object_ = workflow.getStateChangeInformation(document, state_object, transition=self) # Update all variables expression_context = None for variable in workflow.getVariableValueList(): if variable.getAutomaticUpdate(): # if we have it in form get it from there # otherwise use default variable_title = variable.getTitle() if variable_title in form_kw: status_dict[variable_title] = form_kw[variable_title] else: expression = variable.getVariableDefaultExpressionInstance() if expression is not None: if expression_context is None: from Products.ERP5Type.Core.Workflow import createExpressionContext from Products.DCWorkflow.Expression import StateChangeInfo expression_context = createExpressionContext( StateChangeInfo(document, self, status_dict)) status_dict[variable_title] = expression( expression_context) # Update all transition variables if form_kw is not None: object_.REQUEST.other.update(form_kw) for variable in self.getTransitionVariableValueList(): status_dict[variable.getCausalityTitle()] = variable.getInitialValue( object=object_) _updateWorkflowHistory(workflow, document, status_dict) # Call the after script _executeAfterScript(self, document, form_kw=form_kw)
def has_permission(self, transition): guard = transition.guard if guard is None: return True for permission in guard.permissions or []: # need to manually check permissions here because # we don't have an object to check against check_parent = True if permission in self.initial_state.permissions: # check if acquire set for initial_state. # if acquire, you can check against parent pinfo = self.initial_state.getPermissionInfo(permission) if pinfo.get('acquired'): check_parent = True else: check_parent = False if len(set(self.folder_roles) & set(pinfo['roles'])) > 0: break if check_parent: if self.sm.checkPermission(permission, self.folder): break else: # no perms valid... return False if guard.roles: for role in guard.roles: if role in self.folder_roles: break else: return False if guard.groups: for group in guard.groups: if group in self.u_groups: break else: return False if guard.expr is not None: econtext = createExprContext( StateChangeInfo(self.folder, aq_parent(aq_parent(self.initial_state)))) res = guard.expr(econtext) if not res: return False return True
def _checkTransitionGuard(self, guard, sm, wf_def, ob): """ This method is similar to DCWorkflow.Guard.check, but allows to retrieve the truth value as a appy.gen.No instance, not simply "1" or "0". """ u_roles = None if wf_def.manager_bypass: # Possibly bypass. u_roles = sm.getRolesInContext(ob) if 'Manager' in u_roles: return 1 if guard.permissions: for p in guard.permissions: if _checkPermission(p, ob): break else: return 0 if guard.roles: # Require at least one of the given roles. if u_roles is None: u_roles = sm.getRolesInContext(ob) for role in guard.roles: if role in u_roles: break else: return 0 if guard.groups: # Require at least one of the specified groups. u = sm.getUser() b = aq_base(u) if hasattr(b, 'getGroupsInContext'): u_groups = u.getGroupsInContext(ob) elif hasattr(b, 'getGroups'): u_groups = u.getGroups() else: u_groups = () for group in guard.groups: if group in u_groups: break else: return 0 expr = guard.expr if expr is not None: econtext = createExprContext(StateChangeInfo(ob, wf_def)) res = expr(econtext) return res return 1
def check(self, sm, wf_def, ob, **kw): """Checks conditions in this guard. """ u_roles = None if wf_def.manager_bypass: # Possibly bypass. u_roles = sm.getUser().getRolesInContext(ob) if 'Manager' in u_roles: return 1 if self.permissions: for p in self.permissions: if _checkPermission(p, ob): break else: return 0 if self.roles: # Require at least one of the given roles. if u_roles is None: u_roles = sm.getUser().getRolesInContext(ob) for role in self.roles: if role in u_roles: break else: return 0 if self.groups: # Require at least one of the specified groups. u = sm.getUser() b = aq_base(u) if hasattr(b, 'getGroupsInContext'): u_groups = u.getGroupsInContext(ob) elif hasattr(b, 'getGroups'): u_groups = u.getGroups() else: u_groups = () for group in self.groups: if group in u_groups: break else: return 0 expr = self.expr if expr is not None: econtext = createExprContext( StateChangeInfo(ob, wf_def, kwargs=kw)) res = expr(econtext) if not res: return 0 return 1
def _executeTransition(self, ob, tdef=None, kwargs=None): ''' Private method. Puts object in a new state. ''' sci = None econtext = None moved_exc = None # Figure out the old and new states. old_sdef = self._getWorkflowStateOf(ob) old_state = old_sdef.getId() if tdef is None: new_state = self.initial_state former_status = {} else: new_state = tdef.new_state_id if not new_state: # Stay in same state. new_state = old_state former_status = self._getStatusOf(ob) new_sdef = self.states.get(new_state, None) if new_sdef is None: msg = _(u'Destination state undefined: ${state_id}', mapping={'state_id': new_state}) raise WorkflowException(msg) # Fire "before" event notify( BeforeTransitionEvent(ob, self, old_sdef, new_sdef, tdef, former_status, kwargs)) # Execute the "before" script. if tdef is not None and tdef.script_name: script = self.scripts[tdef.script_name] # Pass lots of info to the script in a single parameter. sci = StateChangeInfo(ob, self, former_status, tdef, old_sdef, new_sdef, kwargs) try: script(sci) # May throw an exception. except ObjectMoved, moved_exc: ob = moved_exc.getNewObject()
def notifyBefore(self, ob, transition_list, args=None, kw=None): ''' Notifies this workflow of an action before it happens, allowing veto by exception. Unless an exception is thrown, either a notifySuccess() or notifyException() can be expected later on. The action usually corresponds to a method name. ''' if type(transition_list) in StringTypes: return # Wrap args into kw since this is the only way # to be compatible with DCWorkflow # A better approach consists in extending DCWorkflow if kw is None: kw = {'workflow_method_args': args} else: kw = kw.copy() kw['workflow_method_args'] = args filtered_transition_list = [] for t_id in transition_list: tdef = self.interactions[t_id] assert tdef.trigger_type == TRIGGER_WORKFLOW_METHOD filtered_transition_list.append(tdef.id) former_status = self._getStatusOf(ob) # Execute the "before" script. for script_name in tdef.script_name: script = self.scripts[script_name] # Pass lots of info to the script in a single parameter. sci = StateChangeInfo(ob, self, former_status, tdef, None, None, kwargs=kw) script(sci) # May throw an exception return filtered_transition_list
def getInfoFor(self, ob, name, default): ''' Allows the user to request information provided by the workflow. This method must perform its own security checks. ''' vdef = self.variables.get(name, _MARKER) if vdef is _MARKER: return default if vdef.info_guard is not None and not vdef.info_guard.check( getSecurityManager(), self, ob): return default status = self._getStatusOf(ob) if status is not None and status.has_key(name): value = status[name] # Not set yet. Use a default. elif vdef.default_expr is not None: ec = createExprContext(StateChangeInfo(ob, self, status)) value = vdef.default_expr(ec) else: value = vdef.default_value return value
expr = tdef_exprs[id] elif not vdef.update_always and former_status.has_key(id): # Preserve former value value = former_status[id] else: if vdef.default_expr is not None: expr = vdef.default_expr else: value = vdef.default_value if expr is not None: # Evaluate an expression. if econtext is None: # Lazily create the expression context. if sci is None: sci = StateChangeInfo( ob, self, former_status, tdef, old_sdef, new_sdef, kwargs) econtext = createExprContext(sci) value = expr(econtext) status[id] = value # Update state. status[self.state_var] = new_state tool = aq_parent(aq_inner(self)) tool.setStatusOf(self.id, ob, status) # Update role to permission assignments. self.updateRoleMappingsFor(ob) # Execute the "after" script. if tdef is not None and tdef.after_script_name:
def _executeTransition(self, ob, tdef=None, kwargs=None): ''' Private method. Puts object in a new state. ''' sci = None econtext = None moved_exc = None # Figure out the old and new states. old_sdef = self._getWorkflowStateOf(ob) old_state = old_sdef.getId() if tdef is None: new_state = self.initial_state former_status = {} else: new_state = tdef.new_state_id if not new_state: # Stay in same state. new_state = old_state former_status = self._getStatusOf(ob) new_sdef = self.states.get(new_state, None) if new_sdef is None: msg = _(u'Destination state undefined: ${state_id}', mapping={'state_id': new_state}) raise WorkflowException(msg) # Fire "before" event notify(BeforeTransitionEvent(ob, self, old_sdef, new_sdef, tdef, former_status, kwargs)) # Execute the "before" script. if tdef is not None and tdef.script_name: script = self.scripts[tdef.script_name] # Pass lots of info to the script in a single parameter. sci = StateChangeInfo( ob, self, former_status, tdef, old_sdef, new_sdef, kwargs) try: script(sci) # May throw an exception. except ObjectMoved as moved_exc: ob = moved_exc.getNewObject() # Re-raise after transition # Update variables. state_values = new_sdef.var_values if state_values is None: state_values = {} tdef_exprs = None if tdef is not None: tdef_exprs = tdef.var_exprs if tdef_exprs is None: tdef_exprs = {} status = {} for id, vdef in self.variables.items(): if not vdef.for_status: continue expr = None if id in state_values: value = state_values[id] elif id in tdef_exprs: expr = tdef_exprs[id] elif not vdef.update_always and id in former_status: # Preserve former value value = former_status[id] else: if vdef.default_expr is not None: expr = vdef.default_expr else: value = vdef.default_value if expr is not None: # Evaluate an expression. if econtext is None: # Lazily create the expression context. if sci is None: sci = StateChangeInfo( ob, self, former_status, tdef, old_sdef, new_sdef, kwargs) econtext = createExprContext(sci) value = expr(econtext) status[id] = value # Update state. status[self.state_var] = new_state tool = aq_parent(aq_inner(self)) tool.setStatusOf(self.id, ob, status) # Update role to permission assignments. self.updateRoleMappingsFor(ob) # Execute the "after" script. if tdef is not None and tdef.after_script_name: script = self.scripts[tdef.after_script_name] # Pass lots of info to the script in a single parameter. sci = StateChangeInfo( ob, self, status, tdef, old_sdef, new_sdef, kwargs) script(sci) # May throw an exception. # Fire "after" event notify(AfterTransitionEvent(ob, self, old_sdef, new_sdef, tdef, status, kwargs)) # Return the new state object. if moved_exc is not None: # Propagate the notification that the object has moved. raise moved_exc else: return new_sdef
def notifySuccess(self, ob, transition_list, result, args=None, kw=None): """ Notifies this workflow that an action has taken place. """ if isinstance(transition_list, basestring): return if kw is None: kw = {} else: kw = kw.copy() kw['workflow_method_args'] = args kw['workflow_method_result'] = result workflow_variable_list = self.getVariableValueList() for t_id in transition_list: tdef = self.getTransitionValueByReference(t_id) assert tdef.getTriggerType() == TRIGGER_WORKFLOW_METHOD # Initialize variables former_status = self._getStatusOf(ob) econtext = None sci = None # Update variables. status = {} for vdef in workflow_variable_list: id_ = vdef.getId() if not vdef.getStatusIncluded(): continue expression = None value = '' if not vdef.getAutomaticUpdate() and id_ in former_status: # Preserve former value value = former_status[id_] else: variable_default_expression = vdef.getVariableDefaultExpression() if variable_default_expression is not None: expression = variable_default_expression if expression is not None: # Evaluate an expression. if econtext is None: # Lazily create the expression context. if sci is None: sci = StateChangeInfo( ob, self, former_status, tdef, None, None, None) econtext = createExpressionContext(sci) value = expression(econtext) status[id_] = value sci = StateChangeInfo( ob, self, former_status, tdef, None, None, kwargs=kw) # Execute the "after" script. for script in tdef.getAfterScriptValueList(): script(sci) # May throw an exception. # Queue the "Before Commit" scripts sm = getSecurityManager() for script in tdef.getBeforeCommitScriptValueList(): transaction.get().addBeforeCommitHook(self._before_commit, (sci, script.getId(), sm)) # Execute "activity" scripts for script in tdef.getActivateScriptValueList(): ob.activate(activity='SQLQueue').activeInteractionScript( interaction_workflow_path=self.getPhysicalPath(), script_name=script.getId(), status=status, tdef_id=tdef.getId(), )
def activeScript(self, script_name, ob_url, status, tdef_id): ob = self.unrestrictedTraverse(ob_url) tdef = self.getTransitionValueByReference(tdef_id) sci = StateChangeInfo(ob, self, status, tdef, None, None, None) self._getOb(script_name)(sci)
def notifySuccess(self, ob, transition_list, result, args=None, kw=None): ''' Notifies this workflow that an action has taken place. ''' if type(transition_list) in StringTypes: return kw = kw.copy() kw['workflow_method_args'] = args kw['workflow_method_result'] = result for t_id in transition_list: tdef = self.interactions[t_id] assert tdef.trigger_type == TRIGGER_WORKFLOW_METHOD # Initialize variables former_status = self._getStatusOf(ob) econtext = None sci = None # Update variables. tdef_exprs = tdef.var_exprs if tdef_exprs is None: tdef_exprs = {} status = {} for id, vdef in self.variables.items(): if not vdef.for_status: continue expr = None if tdef_exprs.has_key(id): expr = tdef_exprs[id] elif not vdef.update_always and former_status.has_key(id): # Preserve former value value = former_status[id] else: if vdef.default_expr is not None: expr = vdef.default_expr else: value = vdef.default_value if expr is not None: # Evaluate an expression. if econtext is None: # Lazily create the expression context. if sci is None: sci = StateChangeInfo(ob, self, former_status, tdef, None, None, None) econtext = createExprContext(sci) value = expr(econtext) status[id] = value sci = StateChangeInfo(ob, self, former_status, tdef, None, None, kwargs=kw) # Execute the "after" script. for script_name in tdef.after_script_name: script = self.scripts[script_name] # Pass lots of info to the script in a single parameter. script(sci) # May throw an exception # Queue the "Before Commit" scripts sm = getSecurityManager() for script_name in tdef.before_commit_script_name: transaction.get().addBeforeCommitHook(self._before_commit, (sci, script_name, sm)) # Execute "activity" scripts for script_name in tdef.activate_script_name: self.activate(activity='SQLQueue')\ .activeScript(script_name, ob.getRelativeUrl(), status, tdef.id)