415 hm.register_hook(after_add_in_group, 'after_add_relation', 'in_group') |
415 hm.register_hook(after_add_in_group, 'after_add_relation', 'in_group') |
416 hm.register_hook(after_del_in_group, 'after_delete_relation', 'in_group') |
416 hm.register_hook(after_del_in_group, 'after_delete_relation', 'in_group') |
417 |
417 |
418 |
418 |
419 # workflow handling ########################################################### |
419 # workflow handling ########################################################### |
|
420 |
|
421 def _change_state(session, x, oldstate, newstate): |
|
422 nocheck = session.transaction_data.setdefault('skip-security', set()) |
|
423 nocheck.add((x, 'in_state', oldstate)) |
|
424 nocheck.add((x, 'in_state', newstate)) |
|
425 # delete previous state first in case we're using a super session |
|
426 session.delete_relation(x, 'in_state', oldstate) |
|
427 session.add_relation(x, 'in_state', newstate) |
|
428 |
420 |
429 |
421 def before_add_trinfo(session, entity): |
430 def before_add_trinfo(session, entity): |
422 """check the transition is allowed, add missing information. Expect that: |
431 """check the transition is allowed, add missing information. Expect that: |
423 * wf_info_for inlined relation is set |
432 * wf_info_for inlined relation is set |
424 * by_transition or to_state (managers only) inlined relation is set |
433 * by_transition or to_state (managers only) inlined relation is set |
475 entity['to_state'] = deststateeid |
484 entity['to_state'] = deststateeid |
476 nocheck = session.transaction_data.setdefault('skip-security', set()) |
485 nocheck = session.transaction_data.setdefault('skip-security', set()) |
477 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
486 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
478 nocheck.add((entity.eid, 'to_state', deststateeid)) |
487 nocheck.add((entity.eid, 'to_state', deststateeid)) |
479 |
488 |
|
489 |
480 def after_add_trinfo(session, entity): |
490 def after_add_trinfo(session, entity): |
481 """change related entity state""" |
491 """change related entity state""" |
482 # need to delete previous state first, not done automatically since |
492 _change_state(session, entity['wf_info_for'], |
483 # we're using a super session |
493 entity['from_state'], entity['to_state']) |
484 session.unsafe_execute('DELETE X in_state S WHERE X eid %(x)s, S eid %(s)s', |
|
485 {'x': entity['wf_info_for'], 's': entity['from_state']}, |
|
486 ('x', 's')) |
|
487 session.unsafe_execute('SET X in_state S WHERE X eid %(x)s, S eid %(s)s', |
|
488 {'x': entity['wf_info_for'], 's': entity['to_state']}, |
|
489 ('x', 's')) |
|
490 |
494 |
491 |
495 |
492 class SetInitialStateOp(PreCommitOperation): |
496 class SetInitialStateOp(PreCommitOperation): |
493 """make initial state be a default state""" |
497 """make initial state be a default state""" |
494 |
498 |
508 |
512 |
509 |
513 |
510 def set_initial_state_after_add(session, entity): |
514 def set_initial_state_after_add(session, entity): |
511 SetInitialStateOp(session, entity=entity) |
515 SetInitialStateOp(session, entity=entity) |
512 |
516 |
|
517 |
|
518 class WorkflowChangedOp(PreCommitOperation): |
|
519 """fix entity current state when changing its workflow""" |
|
520 |
|
521 def precommit_event(self): |
|
522 session = self.session |
|
523 pendingeids = session.transaction_data.get('pendingeids', ()) |
|
524 if self.eid in pendingeids: |
|
525 return |
|
526 entity = session.entity_from_eid(self.eid) |
|
527 # notice that enforcment that new workflow apply to the entity's type is |
|
528 # done by schema rule, no need to check it here |
|
529 if entity.current_workflow.eid == self.wfeid: |
|
530 deststate = entity.current_workflow.initial |
|
531 if not deststate: |
|
532 msg = session._('workflow has no initial state') |
|
533 raise ValidationError(entity.eid, {'custom_workflow': msg}) |
|
534 if entity.current_workflow.state_by_eid(entity.current_state.eid): |
|
535 # nothing to do |
|
536 return |
|
537 # if there are no history, simply go to new workflow's initial state |
|
538 if not entity.workflow_history: |
|
539 if entity.current_state.eid != deststate.eid: |
|
540 _change_state(session, entity.eid, |
|
541 entity.current_state.eid, deststate.eid) |
|
542 return |
|
543 msg = session._('workflow changed to "%s"') |
|
544 msg %= entity.current_workflow.name |
|
545 entity.change_state(deststate.name, msg) |
|
546 |
|
547 |
|
548 def set_custom_workflow(session, eidfrom, rtype, eidto): |
|
549 WorkflowChangedOp(session, eid=eidfrom, wfeid=eidto) |
|
550 |
|
551 |
|
552 def del_custom_workflow(session, eidfrom, rtype, eidto): |
|
553 entity = session.entity_from_eid(eidfrom) |
|
554 typewf = entity.cwetype_workflow() |
|
555 if typewf is not None: |
|
556 WorkflowChangedOp(session, eid=eidfrom, wfeid=typewf.eid) |
|
557 |
|
558 |
513 def after_del_workflow(session, eid): |
559 def after_del_workflow(session, eid): |
514 # workflow cleanup |
560 # workflow cleanup |
515 session.execute('DELETE State X WHERE NOT X state_of Y') |
561 session.execute('DELETE State X WHERE NOT X state_of Y') |
516 session.execute('DELETE Transition X WHERE NOT X transition_of Y') |
562 session.execute('DELETE Transition X WHERE NOT X transition_of Y') |
517 |
563 |
524 #hm.register_hook(relation_deleted, 'before_delete_relation', 'in_state') |
570 #hm.register_hook(relation_deleted, 'before_delete_relation', 'in_state') |
525 for eschema in hm.schema.entities(): |
571 for eschema in hm.schema.entities(): |
526 if 'in_state' in eschema.subject_relations(): |
572 if 'in_state' in eschema.subject_relations(): |
527 hm.register_hook(set_initial_state_after_add, 'after_add_entity', |
573 hm.register_hook(set_initial_state_after_add, 'after_add_entity', |
528 str(eschema)) |
574 str(eschema)) |
|
575 hm.register_hook(set_custom_workflow, 'after_add_relation', 'custom_workflow') |
|
576 hm.register_hook(del_custom_workflow, 'after_delete_relation', 'custom_workflow') |
529 hm.register_hook(after_del_workflow, 'after_delete_entity', 'Workflow') |
577 hm.register_hook(after_del_workflow, 'after_delete_entity', 'Workflow') |
530 |
578 |
531 |
579 |
532 # CWProperty hooks ############################################################# |
580 # CWProperty hooks ############################################################# |
533 |
581 |