21 WorkflowTransitionEvent, ConditionFailedError, NoTransitionAvailableError, AmbiguousTransitionError |
21 WorkflowTransitionEvent, ConditionFailedError, NoTransitionAvailableError, AmbiguousTransitionError |
22 |
22 |
23 # import packages |
23 # import packages |
24 from pyams_utils.adapter import adapter_config |
24 from pyams_utils.adapter import adapter_config |
25 from pyams_utils.registry import get_utility |
25 from pyams_utils.registry import get_utility |
26 from pyams_utils.request import check_request |
26 from pyams_utils.request import check_request, query_request |
27 from pyams_utils.traversing import get_parent |
27 from pyams_utils.traversing import get_parent |
28 from pyams_utils.vocabulary import vocabulary_config |
28 from pyams_utils.vocabulary import vocabulary_config |
29 from pyramid.httpexceptions import HTTPUnauthorized |
29 from pyramid.httpexceptions import HTTPUnauthorized |
30 from pyramid.threadlocal import get_current_registry |
30 from zope.component.globalregistry import getGlobalSiteManager |
31 from zope.componentvocabulary.vocabulary import UtilityVocabulary |
31 from zope.componentvocabulary.vocabulary import UtilityVocabulary |
32 from zope.interface import implementer |
32 from zope.interface import implementer |
33 from zope.lifecycleevent import ObjectModifiedEvent |
33 from zope.lifecycleevent import ObjectModifiedEvent |
34 |
34 |
35 from pyams_workflow import _ |
35 from pyams_workflow import _ |
85 readonly_states=None, |
85 readonly_states=None, |
86 protected_states=None, |
86 protected_states=None, |
87 manager_states=None, |
87 manager_states=None, |
88 published_states=None, |
88 published_states=None, |
89 waiting_states=None, |
89 waiting_states=None, |
90 retired_states=None): |
90 retired_states=None, |
|
91 auto_retired_state=None): |
91 self.refresh(transitions) |
92 self.refresh(transitions) |
92 self.states = states |
93 self.states = states |
93 self.initial_state = initial_state |
94 self.initial_state = initial_state |
94 self.update_states = set(update_states) if update_states else set() |
95 self.update_states = set(update_states) if update_states else set() |
95 self.readonly_states = set(readonly_states) if readonly_states else set() |
96 self.readonly_states = set(readonly_states) if readonly_states else set() |
96 self.protected_states = set(protected_states) if protected_states else set() |
97 self.protected_states = set(protected_states) if protected_states else set() |
97 self.manager_states = set(manager_states) if manager_states else set() |
98 self.manager_states = set(manager_states) if manager_states else set() |
98 self.published_states = set(published_states) if published_states else set() |
99 self.published_states = set(published_states) if published_states else set() |
99 self.waiting_states = set(waiting_states) if waiting_states else set() |
100 self.waiting_states = set(waiting_states) if waiting_states else set() |
100 self.retired_states = set(retired_states) if retired_states else set() |
101 self.retired_states = set(retired_states) if retired_states else set() |
|
102 self.auto_retired_state = auto_retired_state |
101 |
103 |
102 def _register(self, transition): |
104 def _register(self, transition): |
103 transitions = self._sources.setdefault(transition.source, {}) |
105 transitions = self._sources.setdefault(transition.source, {}) |
104 transitions[transition.transition_id] = transition |
106 transitions[transition.transition_id] = transition |
105 self._id_transitions[transition.transition_id] = transition |
107 self._id_transitions[transition.transition_id] = transition |
163 raise HTTPUnauthorized() |
165 raise HTTPUnauthorized() |
164 # now make sure transition can still work in this context |
166 # now make sure transition can still work in this context |
165 if not transition.condition(self, self.context): |
167 if not transition.condition(self, self.context): |
166 raise ConditionFailedError() |
168 raise ConditionFailedError() |
167 # perform action, return any result as new version |
169 # perform action, return any result as new version |
|
170 if principal is None: |
|
171 request = query_request() |
|
172 if request is not None: |
|
173 principal = request.principal |
168 result = transition.action(self, self.context) |
174 result = transition.action(self, self.context) |
169 if result is not None: |
175 if result is not None: |
170 # clear result history |
|
171 IWorkflowState(result).history.clear() |
|
172 # stamp it with version |
176 # stamp it with version |
173 versions.add_version(result, transition.destination) |
177 versions.add_version(result, transition.destination, principal) |
174 # execute any side effect: |
178 # execute any side effect: |
175 if side_effect is not None: |
179 if side_effect is not None: |
176 side_effect(result) |
180 side_effect(result) |
177 event = WorkflowVersionTransitionEvent(result, self.wf, self.context, |
181 event = WorkflowVersionTransitionEvent(result, self.wf, principal, self.context, |
178 transition.source, |
182 transition.source, |
179 transition.destination, |
183 transition.destination, |
180 transition, comment) |
184 transition, comment) |
181 else: |
185 else: |
182 versions.set_state(state.version_id, transition.destination) |
186 versions.set_state(state.version_id, transition.destination, principal) |
183 # execute any side effect |
187 # execute any side effect |
184 if side_effect is not None: |
188 if side_effect is not None: |
185 side_effect(self.context) |
189 side_effect(self.context) |
186 event = WorkflowTransitionEvent(self.context, self.wf, |
190 event = WorkflowTransitionEvent(self.context, self.wf, principal, |
187 transition.source, |
191 transition.source, |
188 transition.destination, |
192 transition.destination, |
189 transition, comment) |
193 transition, comment) |
190 # change state of context or new object |
194 # change state of context or new object |
191 registry = get_current_registry() |
195 registry = getGlobalSiteManager() |
192 registry.notify(event) |
196 registry.notify(event) |
193 # send modified event for original or new object |
197 # send modified event for original or new object |
194 if result is None: |
198 if result is None: |
195 registry.notify(ObjectModifiedEvent(self.context)) |
199 registry.notify(ObjectModifiedEvent(self.context)) |
196 else: |
200 else: |
197 registry.notify(ObjectModifiedEvent(result)) |
201 registry.notify(ObjectModifiedEvent(result)) |
198 return result |
202 return result |
199 |
203 |
200 def fire_transition_toward(self, state, comment=None, side_effect=None, check_security=True): |
204 def fire_transition_toward(self, state, comment=None, side_effect=None, check_security=True, principal=None): |
|
205 current_state = IWorkflowState(self.context) |
201 transition_ids = self.get_fireable_transition_ids_toward(state, check_security) |
206 transition_ids = self.get_fireable_transition_ids_toward(state, check_security) |
202 if not transition_ids: |
207 if not transition_ids: |
203 raise NoTransitionAvailableError(self.state(self.context).get_state(), state) |
208 raise NoTransitionAvailableError(current_state.state, state) |
204 if len(transition_ids) != 1: |
209 if len(transition_ids) != 1: |
205 raise AmbiguousTransitionError(self.state(self.context).get_state(), state) |
210 raise AmbiguousTransitionError(current_state.state, state) |
206 return self.fire_transition(transition_ids[0], comment, side_effect, check_security) |
211 return self.fire_transition(transition_ids[0], comment, side_effect, check_security, principal) |
207 |
212 |
208 def fire_transition_for_versions(self, state, transition_id, comment=None): |
213 def fire_transition_for_versions(self, state, transition_id, comment=None, principal=None): |
209 versions = IWorkflowVersions(self.parent) |
214 versions = IWorkflowVersions(self.parent) |
210 for version in versions.get_versions(state): |
215 for version in versions.get_versions(state): |
211 IWorkflowInfo(version).fire_transition(transition_id, comment) |
216 IWorkflowInfo(version).fire_transition(transition_id, comment, principal=principal) |
212 |
217 |
213 def fire_automatic(self): |
218 def fire_automatic(self): |
214 for transition_id in self.get_automatic_transition_ids(): |
219 for transition_id in self.get_automatic_transition_ids(): |
215 try: |
220 try: |
216 self.fire_transition(transition_id) |
221 self.fire_transition(transition_id) |