[schema, cleanup] one more case for add_etype_button
# copyright 2010-2011 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/>."""Specific views for data sources and related entities (eg CWSource,CWSourceHostConfig, CWSourceSchemaConfig)."""__docformat__="restructuredtext en"_=unicodefromitertoolsimportrepeat,chainfromcubicwebimportUnauthorizedfromcubicweb.selectorsimportis_instance,score_entity,match_user_groupsfromcubicweb.viewimportEntityView,StartupViewfromcubicweb.schemaimportMETA_RTYPES,VIRTUAL_RTYPES,display_namefromcubicweb.webimportuicfg,formwidgetsaswdgsfromcubicweb.web.viewsimporttabs,actions,ibreadcrumbs,add_etype_button_abaa=uicfg.actionbox_appearsin_addmenu# there are explicit 'add' buttons for those_abaa.tag_object_of(('CWSourceSchemaConfig','cw_schema','*'),False)_abaa.tag_object_of(('CWSourceSchemaConfig','cw_for_source','*'),False)_abaa.tag_object_of(('CWSourceSchemaConfig','cw_host_config_of','*'),False)_afs=uicfg.autoform_section_afs.tag_attribute(('CWSource','synchronizing'),'main','hidden')_afs.tag_object_of(('*','cw_for_source','CWSource'),'main','hidden')_affk=uicfg.autoform_field_kwargs_affk.tag_attribute(('CWSource','parser'),{'widget':wdgs.TextInput})# source primary views #########################################################_pvs=uicfg.primaryview_section_pvs.tag_attribute(('CWSource','name'),'hidden')_pvs.tag_object_of(('*','cw_for_source','CWSource'),'hidden')_pvs.tag_object_of(('*','cw_host_config_of','CWSource'),'hidden')_pvdc=uicfg.primaryview_display_ctrl_pvdc.tag_attribute(('CWSource','type'),{'vid':'attribute'})# disable reledit_rc=uicfg.reledit_ctrl_rc.tag_attribute(('CWSource','config'),{'rvid':'verbatimattr'})_rc.tag_attribute(('CWSourceHostConfig','config'),{'rvid':'verbatimattr'})_rc.tag_attribute(('CWSourceSchemaConfig','options'),{'rvid':'verbatimattr'})classCWSourcePrimaryView(tabs.TabbedPrimaryView):__select__=is_instance('CWSource')tabs=[_('cwsource-main'),_('cwsource-mapping')]default_tab='cwsource-main'classCWSourceMainTab(tabs.PrimaryTab):__regid__='cwsource-main'__select__=tabs.PrimaryTab.__select__&is_instance('CWSource')defrender_entity_attributes(self,entity):super(CWSourceMainTab,self).render_entity_attributes(entity)self.w(add_etype_button(self._cw,'CWSourceHostConfig',__linkto='cw_host_config_of:%s:subject'%entity.eid,__redirectpath=entity.rest_path()))try:hostconfig=self._cw.execute('Any X, XC, XH WHERE X cw_host_config_of S, S eid %(s)s, ''X config XC, X match_host XH',{'s':entity.eid})exceptUnauthorized:passelse:ifhostconfig:self.w(u'<h3>%s</h3>'%self._cw._('CWSourceHostConfig_plural'))self._cw.view('editable-table',hostconfig,displaycols=range(2),w=self.w)MAPPED_SOURCE_TYPES=set(('pyrorql','datafeed'))classCWSourceMappingTab(EntityView):__regid__='cwsource-mapping'__select__=(tabs.PrimaryTab.__select__&is_instance('CWSource')&match_user_groups('managers')&score_entity(lambdax:x.typeinMAPPED_SOURCE_TYPES))defentity_call(self,entity):_=self._cw._self.w('<h3>%s</h3>'%_('Entity and relation supported by this source'))self.w(add_etype_button(self._cw,'CWSourceSchemaConfig',__linkto='cw_for_source:%s:subject'%entity.eid))self.w(u'<div class="clear"></div>')rset=self._cw.execute('Any X, SCH, XO ORDERBY ET WHERE X options XO, X cw_for_source S, S eid %(s)s, ''X cw_schema SCH, SCH is ET',{'s':entity.eid})self.wview('table',rset,'noresult')# self.w('<h3>%s</h3>' % _('Relations that should not be crossed'))# self.w('<p>%s</p>' % _(# 'By default, when a relation is not supported by a source, it is '# 'supposed that a local relation may point to an entity from the '# 'external source. Relations listed here won\'t have this '# '"crossing" behaviour.'))# self.wview('list', entity.related('cw_dont_cross'), 'noresult')# self.w('<h3>%s</h3>' % _('Relations that can be crossed'))# self.w('<p>%s</p>' % _(# 'By default, when a relation is supported by a source, it is '# 'supposed that a local relation can\'t point to an entity from the '# 'external source. Relations listed here may have this '# '"crossing" behaviour anyway.'))# self.wview('list', entity.related('cw_may_cross'), 'noresult')checker=MAPPING_CHECKERS.get(entity.type,MappingChecker)(entity)checker.check()if(checker.errorsorchecker.warningsorchecker.infos):self.w('<h2>%s</h2>'%_('Detected problems'))errors=zip(repeat(_('error')),checker.errors)warnings=zip(repeat(_('warning')),checker.warnings)infos=zip(repeat(_('warning')),checker.infos)self.wview('pyvaltable',pyvalue=chain(errors,warnings,infos))classMappingChecker(object):def__init__(self,cwsource):self.cwsource=cwsourceself.errors=[]self.warnings=[]self.infos=[]self.schema=cwsource._cw.vreg.schemadefinit(self):# supported entity typesself.sentities=set()# supported relationsself.srelations={}# avoid duplicated messagesself.seen=set()# first get mapping as dict/setsforschemacfginself.cwsource.reverse_cw_for_source:self.init_schemacfg(schemacfg)definit_schemacfg(self,schemacfg):cwerschema=schemacfg.schemaifcwerschema.__regid__=='CWEType':self.sentities.add(cwerschema.name)elifcwerschema.__regid__=='CWRType':assertnotcwerschema.nameinself.srelationsself.srelations[cwerschema.name]=Noneelse:# CWAttribute/CWRelationself.srelations.setdefault(cwerschema.rtype.name,[]).append((cwerschema.stype.name,cwerschema.otype.name))self.sentities.add(cwerschema.stype.name)self.sentities.add(cwerschema.otype.name)defcheck(self):self.init()error=self.errors.appendwarning=self.warnings.appendinfo=self.infos.appendforetypeinself.sentities:eschema=self.schema[etype]forrschema,ttypes,roleineschema.relation_definitions():ifrschemainMETA_RTYPES:continuettypes=[ttypeforttypeinttypesifttypeinself.sentities]ifnotrschemainself.srelations:forttypeinttypes:rdef=rschema.role_rdef(etype,ttype,role)self.seen.add(rdef)ifrdef.role_cardinality(role)in'1+':error(_('relation %(type)s with %(etype)s as %(role)s ''and target type %(target)s is mandatory but ''not supported')%{'rtype':rschema,'etype':etype,'role':role,'target':ttype})elifttypeinself.sentities:warning(_('%s could be supported')%rdef)elifnotttypes:warning(_('relation %(rtype)s with %(etype)s as %(role)s is ''supported but no target type supported')%{'rtype':rschema,'role':role,'etype':etype})forrtype,rdefsinself.srelations.iteritems():ifrdefsisNone:rschema=self.schema[rtype]forsubj,objinrschema.rdefs:ifsubjinself.sentitiesandobjinself.sentities:breakelse:error(_('relation %s is supported but none of its definitions ''matches supported entities')%rtype)self.custom_check()defcustom_check(self):passclassPyroRQLMappingChecker(MappingChecker):"""pyrorql source mapping checker"""definit(self):self.dontcross=set()self.maycross=set()super(PyroRQLMappingChecker,self).init()definit_schemacfg(self,schemacfg):options=schemacfg.optionsor()if'dontcross'inoptions:self.dontcross.add(schemacfg.schema.name)else:super(PyroRQLMappingChecker,self).init_schemacfg(schemacfg)if'maycross'inoptions:self.maycross.add(schemacfg.schema.name)defcustom_check(self):error=self.errors.appendinfo=self.infos.appendforetypeinself.sentities:eschema=self.schema[etype]forrschema,ttypes,roleineschema.relation_definitions():ifrschemainMETA_RTYPES:continueifnotrschemainself.srelations:ifrschemanotinself.dontcross:ifrole=='subject'andrschema.inlined:error(_('inlined relation %(rtype)s of %(etype)s ''should be supported')%{'rtype':rschema,'etype':etype})elif(rschemanotinself.seenandrschemanotinself.maycross):info(_('you may want to specify something for %s')%rschema)self.seen.add(rschema)elifrschemainself.maycrossandrschema.inlined:error(_('you should un-inline relation %s which is ''supported and may be crossed ')%rschema)MAPPING_CHECKERS={'pyrorql':PyroRQLMappingChecker,}# sources management view ######################################################classManageSourcesAction(actions.ManagersAction):__regid__='cwsource'title=_('data sources')category='manage'classCWSourceManagementView(StartupView):__regid__='cw.source-management'rql=('Any S, ST, SP, SD, SN ORDERBY SN WHERE S is CWSource, S name SN, S type ST, ''S latest_retrieval SD, S parser SP')title=_('data sources management')defcall(self,**kwargs):self.w('<h1>%s</h1>'%self._cw._(self.title))self.w(add_etype_button(self._cw,'CWSource'))self.w(u'<div class="clear"></div>')self.wview('table',self._cw.execute(self.rql),displaycols=range(4))# breadcrumbs configuration ####################################################classCWsourceConfigIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter):__select__=is_instance('CWSourceHostConfig','CWSourceSchemaConfig')defparent_entity(self):returnself.entity.cwsource