diff -r 06daf13195d4 -r 107ba1c45227 hooks/workflow.py --- a/hooks/workflow.py Fri Aug 14 11:13:18 2009 +0200 +++ b/hooks/workflow.py Fri Aug 14 11:14:10 2009 +0200 @@ -7,12 +7,32 @@ """ __docformat__ = "restructuredtext en" -from cubicweb import ValidationError +from datetime import datetime + +from cubicweb import RepositoryError, ValidationError from cubicweb.interfaces import IWorkflowable from cubicweb.selectors import entity_implements -from cubicweb.server.hook import Hook, match_rtype -from cubicweb.server.pool import PreCommitOperation -from cubicweb.server.hookhelper import previous_state +from cubicweb.server import hook + + +def previous_state(session, eid): + """return the state of the entity with the given eid, + usually since it's changing in the current transaction. Due to internal + relation hooks, the relation may has been deleted at this point, so + we have handle that + """ + if session.added_in_transaction(eid): + return + pending = session.transaction_data.get('pendingrelations', ()) + for eidfrom, rtype, eidto in reversed(pending): + if rtype == 'in_state' and eidfrom == eid: + rset = session.execute('Any S,N WHERE S eid %(x)s, S name N', + {'x': eidto}, 'x') + return rset.get_entity(0, 0) + rset = session.execute('Any S,N WHERE X eid %(x)s, X in_state S, S name N', + {'x': eid}, 'x') + if rset: + return rset.get_entity(0, 0) def relation_deleted(session, eidfrom, rtype, eidto): @@ -20,7 +40,7 @@ (eidfrom, rtype, eidto)) -class _SetInitialStateOp(PreCommitOperation): +class _SetInitialStateOp(hook.Operation): """make initial state be a default state""" def precommit_event(self): @@ -28,29 +48,30 @@ entity = self.entity # if there is an initial state and the entity's state is not set, # use the initial state as a default state - pendingeids = session.transaction_data.get('pendingeids', ()) - if not entity.eid in pendingeids and not entity.in_state: + if not session.deleted_in_transaction(entity.eid) and not entity.in_state: rset = session.execute('Any S WHERE ET initial_state S, ET name %(name)s', {'name': entity.id}) if rset: session.add_relation(entity.eid, 'in_state', rset[0][0]) +class WorkflowHook(hook.Hook): + __abstract__ = True + category = 'worfklow' -class SetInitialStateHook(Hook): + +class SetInitialStateHook(WorkflowHook): __id__ = 'wfsetinitial' - __select__ = Hook.__select__ & entity_implements(IWorkflowable) - category = 'worfklow' + __select__ = WorkflowHook.__select__ & entity_implements(IWorkflowable) events = ('after_add_entity',) def __call__(self): _SetInitialStateOp(self.cw_req, entity=self.entity) -class PrepareStateChangeHook(Hook): +class PrepareStateChangeHook(WorkflowHook): """record previous state information""" __id__ = 'cwdelstate' - __select__ = Hook.__select__ & match_rtype('in_state') - category = 'worfklow' + __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') events = ('before_delete_relation',) def __call__(self): @@ -104,3 +125,22 @@ args['fs'] = state.eid rql = '%s WHERE %s' % (rql, ', '.join(restriction)) session.unsafe_execute(rql, args, 'e') + + +class SetModificationDateOnStateChange(WorkflowHook): + """update entity's modification date after changing its state""" + __id__ = 'wfsyncmdate' + __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') + events = ('after_add_relation',) + + def __call__(self): + if self.cw_req.added_in_transaction(self.eidfrom): + # new entity, not needed + return + entity = self.cw_req.entity_from_eid(self.eidfrom) + try: + entity.set_attributes(modification_date=datetime.now()) + except RepositoryError, ex: + # usually occurs if entity is coming from a read-only source + # (eg ldap user) + self.warning('cant change modification date for %s: %s', entity, ex)