"""Core hooks: workflow related hooks:organization: Logilab:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"fromcubicwebimportValidationErrorfromcubicweb.interfacesimportIWorkflowablefromcubicweb.selectorsimportentity_implementsfromcubicweb.server.hookimportHook,match_rtypefromcubicweb.server.poolimportPreCommitOperationfromcubicweb.server.hookhelperimportprevious_statedefrelation_deleted(session,eidfrom,rtype,eidto):session.transaction_data.setdefault('pendingrelations',[]).append((eidfrom,rtype,eidto))class_SetInitialStateOp(PreCommitOperation):"""make initial state be a default state"""defprecommit_event(self):session=self.sessionentity=self.entity# if there is an initial state and the entity's state is not set,# use the initial state as a default statependingeids=session.transaction_data.get('pendingeids',())ifnotentity.eidinpendingeidsandnotentity.in_state:rset=session.execute('Any S WHERE ET initial_state S, ET name %(name)s',{'name':entity.id})ifrset:session.add_relation(entity.eid,'in_state',rset[0][0])classSetInitialStateHook(Hook):__id__='wfsetinitial'__select__=Hook.__select__&entity_implements(IWorkflowable)category='worfklow'events=('after_add_entity',)def__call__(self):_SetInitialStateOp(self.cw_req,entity=self.entity)classPrepareStateChangeHook(Hook):"""record previous state information"""__id__='cwdelstate'__select__=Hook.__select__&match_rtype('in_state')category='worfklow'events=('before_delete_relation',)def__call__(self):self.cw_req.transaction_data.setdefault('pendingrelations',[]).append((self.eidfrom,self.rtype,self.eidto))classFireTransitionHook(PrepareStateChangeHook):"""check the transition is allowed and record transition information"""__id__='wffiretransition'events=('before_add_relation',)def__call__(self):session=self.cw_reqeidfrom=self.eidfromeidto=self.eidtostate=previous_state(session,eidfrom)etype=session.describe(eidfrom)[0]ifnot(session.is_super_sessionor'managers'insession.user.groups):ifnotstateisNone:entity=session.entity_from_eid(eidfrom)# we should find at least one transition going to this statetry:iter(state.transitions(entity,eidto)).next()exceptStopIteration:msg=session._('transition is not allowed')raiseValidationError(eidfrom,{'in_state':msg})else:# not a transition# check state is initial state if the workflow defines oneisrset=session.unsafe_execute('Any S WHERE ET initial_state S, ET name %(etype)s',{'etype':etype})ifisrsetandnoteidto==isrset[0][0]:msg=session._('not the initial state for this entity')raiseValidationError(eidfrom,{'in_state':msg})eschema=session.repo.schema[etype]ifnot'wf_info_for'ineschema.object_relations():# workflow history not activated for this entity typereturnrql='INSERT TrInfo T: T wf_info_for E, T to_state DS, T comment %(comment)s'args={'comment':session.get_shared_data('trcomment',None,pop=True),'e':eidfrom,'ds':eidto}cformat=session.get_shared_data('trcommentformat',None,pop=True)ifcformatisnotNone:args['comment_format']=cformatrql+=', T comment_format %(comment_format)s'restriction=['DS eid %(ds)s, E eid %(e)s']ifnotstateisNone:# not a transitionrql+=', T from_state FS'restriction.append('FS eid %(fs)s')args['fs']=state.eidrql='%s WHERE %s'%(rql,', '.join(restriction))session.unsafe_execute(rql,args,'e')