collective.multiworkflow.api#

Workflow-aware equivalents of the plone.api workflow helpers.

Every signature is a pure superset of what plone.api.content offers today: called without workflow_id these behave exactly as their upstream counterparts, reading and driving review_state. Passing workflow_id addresses one specific workflow in the object's chain.

collective.multiworkflow.api.conflicting_permissions(obj: DexterityContent) → dict[str, list[str]][source]#

Find permissions claimed by more than one workflow in the chain.

Concurrent workflows compose safely as long as the permission sets they manage are disjoint: DCWorkflowDefinition.updateRoleMappingsFor only rewrites the permissions listed in that workflow's own permissions, and executing a transition re-applies the mappings of the transitioning workflow alone.

A permission claimed by two workflows is therefore left as whichever of them transitioned last wrote it, and stays that way until the other one transitions or portal_workflow.updateRoleMappings() runs. Use this to audit a site — from an upgrade step, a test, or a debugging session — before trusting a chain's role mappings.

Parameters:

obj -- object whose chain is inspected.

Returns:

mapping of permission to the ids of the workflows managing it, in chain order. Permissions with a single claimant are omitted, so an empty mapping means the chain is conflict-free.

collective.multiworkflow.api.get_state(obj: DexterityContent, default: Any = <object object>, workflow_id: str | None = None) → str[source]#

Get the object's current state, optionally in a specific workflow.

With no workflow_id this is plone.api.content.get_state: it returns review_state. workflow_id selects one workflow from the chain and returns the value of that workflow's state variable.

Parameters:
  • obj -- object to read the state of.

  • default -- returned if the object has no workflow at all.

  • workflow_id -- id of the workflow to read; None means the effective review_state.

Returns:

the current state id.

Raises:
  • InvalidParameterError -- if workflow_id is not registered.

  • WorkflowException -- if the state cannot be determined.

collective.multiworkflow.api.get_states(obj: DexterityContent) → dict[str, str][source]#

Get the object's state in every workflow of its chain.

Parameters:

obj -- object to read the states of.

Returns:

mapping of workflow id to the current state id, in chain order.

collective.multiworkflow.api.owning_workflow(obj: DexterityContent) → dict[str, str][source]#

Map every transition id in the object's chain to its owning workflow.

A transition id defined by more than one workflow is attributed to the first one in chain order that defines it. doActionFor resolves the same collision by state rather than by definition: it executes the id in the first workflow that can execute it from its current state. On a shared id the two can therefore disagree, which is one more reason for transition ids to be unique across a chain.

Parameters:

obj -- object whose chain is inspected.

Returns:

mapping of transition id to workflow id.

collective.multiworkflow.api.transition(obj: DexterityContent, transition: str | None = None, to_state: str | None = None, workflow_id: str | None = None, **kwargs: Any) → None[source]#

Perform a workflow transition, optionally on a specific workflow.

With no workflow_id the transition is routed exactly as plone.api.content.transition routes it — the first workflow in the chain that supports the id wins. Pass workflow_id to address a workflow whose transition id is shadowed by an earlier one in the chain.

Parameters:
  • obj -- object to transition.

  • transition -- id of the transition to perform.

  • to_state -- target state, as an alternative to transition. Only meaningful for the publication workflow, so it may not be combined with workflow_id.

  • workflow_id -- id of the workflow owning the transition.

  • kwargs -- passed through to the workflow, e.g. comment.

Raises:

InvalidParameterError -- if the transition or workflow is invalid, or if to_state and workflow_id are combined.

collective.multiworkflow.api.transitions(obj: DexterityContent) → dict[str, list[str]][source]#

Get the transitions available to the current user, by workflow.

Parameters:

obj -- object to inspect.

Returns:

mapping of workflow id to the ids of its available transitions. Workflows with nothing available are omitted.