17 |
17 |
18 def _change_state(session, x, oldstate, newstate): |
18 def _change_state(session, x, oldstate, newstate): |
19 nocheck = session.transaction_data.setdefault('skip-security', set()) |
19 nocheck = session.transaction_data.setdefault('skip-security', set()) |
20 nocheck.add((x, 'in_state', oldstate)) |
20 nocheck.add((x, 'in_state', oldstate)) |
21 nocheck.add((x, 'in_state', newstate)) |
21 nocheck.add((x, 'in_state', newstate)) |
22 # delete previous state first in case we're using a super session, |
22 # delete previous state first unless in_state isn't stored in the system |
23 # unless in_state isn't stored in the system source |
23 # source |
24 fromsource = session.describe(x)[1] |
24 fromsource = session.describe(x)[1] |
25 if fromsource == 'system' or \ |
25 if fromsource == 'system' or \ |
26 not session.repo.sources_by_uri[fromsource].support_relation('in_state'): |
26 not session.repo.sources_by_uri[fromsource].support_relation('in_state'): |
27 session.delete_relation(x, 'in_state', oldstate) |
27 session.delete_relation(x, 'in_state', oldstate) |
28 session.add_relation(x, 'in_state', newstate) |
28 session.add_relation(x, 'in_state', newstate) |
40 # use the initial state as a default state |
40 # use the initial state as a default state |
41 if not (session.deleted_in_transaction(entity.eid) or entity.in_state) \ |
41 if not (session.deleted_in_transaction(entity.eid) or entity.in_state) \ |
42 and entity.current_workflow: |
42 and entity.current_workflow: |
43 state = entity.current_workflow.initial |
43 state = entity.current_workflow.initial |
44 if state: |
44 if state: |
45 # use super session to by-pass security checks |
45 session.add_relation(entity.eid, 'in_state', state.eid) |
46 session.super_session.add_relation(entity.eid, 'in_state', |
|
47 state.eid) |
|
48 |
46 |
49 |
47 |
50 class _FireAutotransitionOp(hook.Operation): |
48 class _FireAutotransitionOp(hook.Operation): |
51 """try to fire auto transition after state changes""" |
49 """try to fire auto transition after state changes""" |
52 |
50 |
120 if tostate is not None: |
118 if tostate is not None: |
121 # reached an exit point |
119 # reached an exit point |
122 msg = session._('exiting from subworkflow %s') |
120 msg = session._('exiting from subworkflow %s') |
123 msg %= session._(forentity.current_workflow.name) |
121 msg %= session._(forentity.current_workflow.name) |
124 session.transaction_data[(forentity.eid, 'subwfentrytr')] = True |
122 session.transaction_data[(forentity.eid, 'subwfentrytr')] = True |
125 # XXX iirk |
123 forentity.change_state(tostate, msg, u'text/plain', tr=wftr) |
126 req = forentity._cw |
|
127 forentity._cw = session.super_session |
|
128 try: |
|
129 trinfo = forentity.change_state(tostate, msg, u'text/plain', |
|
130 tr=wftr) |
|
131 finally: |
|
132 forentity._cw = req |
|
133 |
124 |
134 |
125 |
135 # hooks ######################################################################## |
126 # hooks ######################################################################## |
136 |
127 |
137 class WorkflowHook(hook.Hook): |
128 class WorkflowHook(hook.Hook): |
193 if fromstate is None: |
184 if fromstate is None: |
194 msg = session._('related entity has no state') |
185 msg = session._('related entity has no state') |
195 raise ValidationError(entity.eid, {None: msg}) |
186 raise ValidationError(entity.eid, {None: msg}) |
196 # True if we are coming back from subworkflow |
187 # True if we are coming back from subworkflow |
197 swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None) |
188 swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None) |
198 cowpowers = session.is_super_session or 'managers' in session.user.groups |
189 cowpowers = ('managers' in session.user.groups |
|
190 or not session.write_security) |
199 # no investigate the requested state change... |
191 # no investigate the requested state change... |
200 try: |
192 try: |
201 treid = entity['by_transition'] |
193 treid = entity['by_transition'] |
202 except KeyError: |
194 except KeyError: |
203 # no transition set, check user is a manager and destination state |
195 # no transition set, check user is a manager and destination state |
264 if forentity.main_workflow.eid != forentity.current_workflow.eid: |
256 if forentity.main_workflow.eid != forentity.current_workflow.eid: |
265 _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo) |
257 _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo) |
266 |
258 |
267 |
259 |
268 class CheckInStateChangeAllowed(WorkflowHook): |
260 class CheckInStateChangeAllowed(WorkflowHook): |
269 """check state apply, in case of direct in_state change using unsafe_execute |
261 """check state apply, in case of direct in_state change using unsafe execute |
270 """ |
262 """ |
271 __regid__ = 'wfcheckinstate' |
263 __regid__ = 'wfcheckinstate' |
272 __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') |
264 __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') |
273 events = ('before_add_relation',) |
265 events = ('before_add_relation',) |
274 |
266 |
305 if self._cw.added_in_transaction(self.eidfrom): |
297 if self._cw.added_in_transaction(self.eidfrom): |
306 # new entity, not needed |
298 # new entity, not needed |
307 return |
299 return |
308 entity = self._cw.entity_from_eid(self.eidfrom) |
300 entity = self._cw.entity_from_eid(self.eidfrom) |
309 try: |
301 try: |
310 entity.set_attributes(modification_date=datetime.now(), |
302 entity.set_attributes(modification_date=datetime.now()) |
311 _cw_unsafe=True) |
|
312 except RepositoryError, ex: |
303 except RepositoryError, ex: |
313 # usually occurs if entity is coming from a read-only source |
304 # usually occurs if entity is coming from a read-only source |
314 # (eg ldap user) |
305 # (eg ldap user) |
315 self.warning('cant change modification date for %s: %s', entity, ex) |
306 self.warning('cant change modification date for %s: %s', entity, ex) |
316 |
307 |