[fti migration] test and fix reindexation of some specific entity types
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""Core hooks: synchronize living session on persistent data changes"""__docformat__="restructuredtext en"fromyams.schemaimportrole_namefromcubicwebimportUnknownProperty,ValidationError,BadConnectionIdfromcubicweb.selectorsimportimplementsfromcubicweb.serverimporthookdefget_user_sessions(repo,ueid):forsessioninrepo._sessions.values():ifueid==session.user.eid:yieldsessionclassSyncSessionHook(hook.Hook):__abstract__=Truecategory='syncsession'# user/groups synchronisation #################################################class_GroupOperation(hook.Operation):"""base class for group operation"""geid=Nonedef__init__(self,session,*args,**kwargs):"""override to get the group name before actual groups manipulation: we may temporarily loose right access during a commit event, so no query should be emitted while comitting """rql='Any N WHERE G eid %(x)s, G name N'result=session.execute(rql,{'x':kwargs['geid']},build_descr=False)hook.Operation.__init__(self,session,*args,**kwargs)self.group=result[0][0]class_DeleteGroupOp(_GroupOperation):"""synchronize user when a in_group relation has been deleted"""defcommit_event(self):"""the observed connections pool has been commited"""groups=self.cnxuser.groupstry:groups.remove(self.group)exceptKeyError:self.error('user %s not in group %s',self.cnxuser,self.group)returnclass_AddGroupOp(_GroupOperation):"""synchronize user when a in_group relation has been added"""defcommit_event(self):"""the observed connections pool has been commited"""groups=self.cnxuser.groupsifself.groupingroups:self.warning('user %s already in group %s',self.cnxuser,self.group)returngroups.add(self.group)classSyncInGroupHook(SyncSessionHook):__regid__='syncingroup'__select__=SyncSessionHook.__select__&hook.match_rtype('in_group')events=('after_delete_relation','after_add_relation')def__call__(self):ifself.event=='after_delete_relation':opcls=_DeleteGroupOpelse:opcls=_AddGroupOpforsessioninget_user_sessions(self._cw.repo,self.eidfrom):opcls(self._cw,cnxuser=session.user,geid=self.eidto)class_DelUserOp(hook.Operation):"""close associated user's session when it is deleted"""def__init__(self,session,cnxid):self.cnxid=cnxidhook.Operation.__init__(self,session)defcommit_event(self):"""the observed connections pool has been commited"""try:self.session.repo.close(self.cnxid)exceptBadConnectionId:pass# already closedclassCloseDeletedUserSessionsHook(SyncSessionHook):__regid__='closession'__select__=SyncSessionHook.__select__&implements('CWUser')events=('after_delete_entity',)def__call__(self):"""modify user permission, need to update users"""forsessioninget_user_sessions(self._cw.repo,self.entity.eid):_DelUserOp(self._cw,session.id)# CWProperty hooks #############################################################class_DelCWPropertyOp(hook.Operation):"""a user's custom properties has been deleted"""defcommit_event(self):"""the observed connections pool has been commited"""try:delself.cwpropdict[self.key]exceptKeyError:self.error('%s has no associated value',self.key)class_ChangeCWPropertyOp(hook.Operation):"""a user's custom properties has been added/changed"""defcommit_event(self):"""the observed connections pool has been commited"""self.cwpropdict[self.key]=self.valueclass_AddCWPropertyOp(hook.Operation):"""a user's custom properties has been added/changed"""defcommit_event(self):"""the observed connections pool has been commited"""cwprop=self.cwpropifnotcwprop.for_user:self.session.vreg['propertyvalues'][cwprop.pkey]=cwprop.value# if for_user is set, update is handled by a ChangeCWPropertyOp operationclassAddCWPropertyHook(SyncSessionHook):__regid__='addcwprop'__select__=SyncSessionHook.__select__&implements('CWProperty')events=('after_add_entity',)def__call__(self):key,value=self.entity.pkey,self.entity.valuesession=self._cwtry:value=session.vreg.typed_value(key,value)exceptUnknownProperty:qname=role_name('pkey','subject')raiseValidationError(self.entity.eid,{qname:session._('unknown property key')})exceptValueError,ex:qname=role_name('value','subject')raiseValidationError(self.entity.eid,{qname:session._(str(ex))})ifnotsession.user.matching_groups('managers'):session.add_relation(self.entity.eid,'for_user',session.user.eid)else:_AddCWPropertyOp(session,cwprop=self.entity)classUpdateCWPropertyHook(AddCWPropertyHook):__regid__='updatecwprop'events=('after_update_entity',)def__call__(self):entity=self.entityifnot('pkey'inentity.edited_attributesor'value'inentity.edited_attributes):returnkey,value=entity.pkey,entity.valuesession=self._cwtry:value=session.vreg.typed_value(key,value)exceptUnknownProperty:returnexceptValueError,ex:qname=role_name('value','subject')raiseValidationError(entity.eid,{qname:session._(str(ex))})ifentity.for_user:forsession_inget_user_sessions(session.repo,entity.for_user[0].eid):_ChangeCWPropertyOp(session,cwpropdict=session_.user.properties,key=key,value=value)else:# site wide properties_ChangeCWPropertyOp(session,cwpropdict=session.vreg['propertyvalues'],key=key,value=value)classDeleteCWPropertyHook(AddCWPropertyHook):__regid__='delcwprop'events=('before_delete_entity',)def__call__(self):eid=self.entity.eidsession=self._cwforeidfrom,rtype,eidtoinsession.transaction_data.get('pendingrelations',()):ifrtype=='for_user'andeidfrom==self.entity.eid:# if for_user was set, delete has already been handledbreakelse:_DelCWPropertyOp(session,cwpropdict=session.vreg['propertyvalues'],key=self.entity.pkey)classAddForUserRelationHook(SyncSessionHook):__regid__='addcwpropforuser'__select__=SyncSessionHook.__select__&hook.match_rtype('for_user')events=('after_add_relation',)def__call__(self):session=self._cweidfrom=self.eidfromifnotsession.describe(eidfrom)[0]=='CWProperty':returnkey,value=session.execute('Any K,V WHERE P eid %(x)s,P pkey K,P value V',{'x':eidfrom})[0]ifsession.vreg.property_info(key)['sitewide']:qname=role_name('for_user','subject')msg=session._("site-wide property can't be set for user")raiseValidationError(eidfrom,{qname:msg})forsession_inget_user_sessions(session.repo,self.eidto):_ChangeCWPropertyOp(session,cwpropdict=session_.user.properties,key=key,value=value)classDelForUserRelationHook(AddForUserRelationHook):__regid__='delcwpropforuser'events=('after_delete_relation',)def__call__(self):session=self._cwkey=session.execute('Any K WHERE P eid %(x)s, P pkey K',{'x':self.eidfrom})[0][0]session.transaction_data.setdefault('pendingrelations',[]).append((self.eidfrom,self.rtype,self.eidto))forsession_inget_user_sessions(session.repo,self.eidto):_DelCWPropertyOp(session,cwpropdict=session_.user.properties,key=key)