[dbapi] retire repo.entity_metas which was used by the dbapi
Related to #3933480.
# copyright 2011-2012 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/>."""cubicweb ldap feed sourceunlike ldapuser source, this source is copy based and will import ldap content(beside passwords for authentication) into the system source."""fromlogilab.common.decoratorsimportcached,cachedpropertyfromlogilab.common.shellutilsimportgenerate_passwordfromcubicwebimportBinary,ConfigurationErrorfromcubicweb.server.utilsimportcrypt_passwordfromcubicweb.server.sourcesimportdatafeedclassDataFeedLDAPAdapter(datafeed.DataFeedParser):__regid__='ldapfeed'# attributes that may appears in source user_attrs dict which are not# attributes of the cw usernon_attribute_keys=set(('email','eid','member','modification_date'))@cachedpropertydefsearchfilterstr(self):""" ldap search string, including user-filter """return'(&%s)'%''.join(self.source.base_filters)@cachedpropertydefsearchgroupfilterstr(self):""" ldap search string, including user-filter """return'(&%s)'%''.join(self.source.group_base_filters)@cachedpropertydefuser_source_entities_by_extid(self):source=self.sourceifsource.user_base_dn.strip():attrs=map(str,source.user_attrs.keys())returndict((userdict['dn'],userdict)foruserdictinsource._search(self._cw,source.user_base_dn,source.user_base_scope,self.searchfilterstr,attrs))return{}@cachedpropertydefgroup_source_entities_by_extid(self):source=self.sourceifsource.group_base_dn.strip():attrs=map(str,['modifyTimestamp']+source.group_attrs.keys())returndict((groupdict['dn'],groupdict)forgroupdictinsource._search(self._cw,source.group_base_dn,source.group_base_scope,self.searchgroupfilterstr,attrs))return{}def_process(self,etype,sdict,raise_on_error=False):self.debug('fetched %s%s',etype,sdict)extid=sdict['dn']entity=self.extid2entity(extid,etype,raise_on_error=raise_on_error,**sdict)ifentityisnotNoneandnotself.created_during_pull(entity):self.notify_updated(entity)attrs=self.ldap2cwattrs(sdict,etype)self.update_if_necessary(entity,attrs)ifetype=='CWUser':self._process_email(entity,sdict)ifetype=='CWGroup':self._process_membership(entity,sdict)defprocess(self,url,raise_on_error=False):"""IDataFeedParser main entry point"""self.debug('processing ldapfeed source %s%s',self.source,self.searchfilterstr)foruserdictinself.user_source_entities_by_extid.itervalues():self._process('CWUser',userdict)self.debug('processing ldapfeed source %s%s',self.source,self.searchgroupfilterstr)forgroupdictinself.group_source_entities_by_extid.itervalues():self._process('CWGroup',groupdict,raise_on_error=raise_on_error)defhandle_deletion(self,config,cnx,myuris):ifconfig['delete-entities']:super(DataFeedLDAPAdapter,self).handle_deletion(config,cnx,myuris)returnifmyuris:byetype={}forextid,(eid,etype)inmyuris.iteritems():ifself.is_deleted(extid,etype,eid):byetype.setdefault(etype,[]).append(str(eid))foretype,eidsinbyetype.iteritems():ifetype!='CWUser':continueself.info('deactivate %s%s entities',len(eids),etype)foreidineids:wf=cnx.entity_from_eid(eid).cw_adapt_to('IWorkflowable')wf.fire_transition_if_possible('deactivate')cnx.commit()defupdate_if_necessary(self,entity,attrs):# disable read security to allow password selectionwithentity._cw.security_enabled(read=False):entity.complete(tuple(attrs))ifentity.cw_etype=='CWUser':wf=entity.cw_adapt_to('IWorkflowable')ifwf.state=='deactivated':wf.fire_transition('activate')self.info('user %s reactivated',entity.login)mdate=attrs.get('modification_date')ifnotmdateormdate>entity.modification_date:attrs=dict((k,v)fork,vinattrs.iteritems()ifv!=getattr(entity,k))ifattrs:entity.cw_set(**attrs)self.notify_updated(entity)defldap2cwattrs(self,sdict,etype,tdict=None):""" Transform dictionary of LDAP attributes to CW etype must be CWUser or CWGroup """iftdictisNone:tdict={}ifetype=='CWUser':items=self.source.user_attrs.iteritems()elifetype=='CWGroup':items=self.source.group_attrs.iteritems()forsattr,tattrinitems:iftattrnotinself.non_attribute_keys:try:tdict[tattr]=sdict[sattr]exceptKeyError:raiseConfigurationError('source attribute %s has not ''been found in the source, ''please check the %s-attrs-map ''field and the permissions of ''the LDAP binding user'%(sattr,etype[2:].lower()))returntdictdefbefore_entity_copy(self,entity,sourceparams):etype=entity.cw_etypeifetype=='EmailAddress':entity.cw_edited['address']=sourceparams['address']else:self.ldap2cwattrs(sourceparams,etype,tdict=entity.cw_edited)ifetype=='CWUser':pwd=entity.cw_edited.get('upassword')ifnotpwd:# generate a dumb password if not fetched from ldap (see# userPassword)pwd=crypt_password(generate_password())entity.cw_edited['upassword']=Binary(pwd)returnentitydefafter_entity_copy(self,entity,sourceparams):super(DataFeedLDAPAdapter,self).after_entity_copy(entity,sourceparams)etype=entity.cw_etypeifetype=='EmailAddress':return# all CWUsers must be treated before CWGroups to have the in_group relation# set correctly in _associate_ldapuserselifetype=='CWUser':groups=filter(None,[self._get_group(name)fornameinself.source.user_default_groups])ifgroups:entity.cw_set(in_group=groups)self._process_email(entity,sourceparams)elifetype=='CWGroup':self._process_membership(entity,sourceparams)defis_deleted(self,extidplus,etype,eid):try:extid,_=extidplus.rsplit('@@',1)exceptValueError:# for some reason extids here tend to come in both forms, e.g:# dn, dn@@Babarextid=extidplusreturnextidnotinself.user_source_entities_by_extiddef_process_email(self,entity,userdict):try:emailaddrs=userdict[self.source.user_rev_attrs['email']]exceptKeyError:return# no email for that user, nothing to doifnotisinstance(emailaddrs,list):emailaddrs=[emailaddrs]foremailaddrinemailaddrs:# search for existing email first, may be coming from another sourcerset=self._cw.execute('EmailAddress X WHERE X address %(addr)s',{'addr':emailaddr})ifnotrset:# not found, create it. first forge an external idemailextid=userdict['dn']+'@@'+emailaddr.encode('utf-8')email=self.extid2entity(emailextid,'EmailAddress',address=emailaddr)entity.cw_set(use_email=email)elifself.sourceuris:# pop from sourceuris anyway, else email may be removed by the# source once import is finisheduri=userdict['dn']+'@@'+emailaddr.encode('utf-8')self.sourceuris.pop(uri,None)# XXX else check use_email relation?def_process_membership(self,entity,sourceparams):""" Find existing CWUsers with the same login as the memberUids in the CWGroup entity and create the in_group relationship """mdate=sourceparams.get('modification_date')if(notmdateormdate>entity.modification_date):self._cw.execute('DELETE U in_group G WHERE G eid %(g)s',{'g':entity.eid})members=sourceparams.get(self.source.group_rev_attrs['member'])ifmembers:members=["'%s'"%eforeinmembers]rql='SET U in_group G WHERE G eid %%(g)s, U login IN (%s)'%','.join(members)self._cw.execute(rql,{'g':entity.eid,})@cacheddef_get_group(self,name):try:returnself._cw.execute('Any X WHERE X is CWGroup, X name %(name)s',{'name':name}).get_entity(0,0)exceptIndexError:self.error('group %r referenced by source configuration %r does not exist',name,self.source.uri)returnNone