[basetemplates] breadcrumbs component context sticks to ApplicationName
# 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/>."""Objects interacting together to provides the external page embedingfunctionality."""__docformat__="restructuredtext en"_=unicodeimportrefromurlparseimporturljoinfromurllib2importurlopen,Request,HTTPErrorfromurllibimportquoteasurlquote# XXX should use view.url_quote methodfromlogilab.mtconverterimportguess_encodingfromcubicweb.selectorsimport(one_line_rset,score_entity,implements,adaptable,match_search_state)fromcubicweb.interfacesimportIEmbedablefromcubicweb.viewimportNOINDEX,NOFOLLOW,EntityAdapter,implements_adapter_compatfromcubicweb.uilibimportsoup2xhtmlfromcubicweb.web.controllerimportControllerfromcubicweb.web.actionimportActionfromcubicweb.web.viewsimportbasetemplatesclassIEmbedableAdapter(EntityAdapter):"""interface for embedable entities"""__regid__='IEmbedable'__select__=implements(IEmbedable,warn=False)# XXX for bw compat, should be abstract@implements_adapter_compat('IEmbedable')defembeded_url(self):"""embed action interface"""raiseNotImplementedErrorclassExternalTemplate(basetemplates.TheMainTemplate):"""template embeding an external web pages into CubicWeb web interface """__regid__='external'defcall(self,body):# XXX fallback to HTML 4 mode when embeding ?self.set_request_content_type()self._cw.search_state=('normal',)self.template_header(self.content_type,None,self._cw._('external page'),[NOINDEX,NOFOLLOW])self.content_header()self.w(body)self.content_footer()self.template_footer()classEmbedController(Controller):__regid__='embed'template='external'defpublish(self,rset=None):req=self._cwif'custom_css'inreq.form:req.add_css(req.form['custom_css'])embedded_url=req.form['url']allowed=self._cw.vreg.config['embed-allowed']_=req._ifallowedisNoneornotallowed.match(embedded_url):body='<h2>%s</h2><h3>%s</h3>'%(_('error while embedding page'),_('embedding this url is forbidden'))else:prefix=req.build_url(self.__regid__,url='')authorization=req.get_header('Authorization')ifauthorization:headers={'Authorization':authorization}else:headers={}try:body=embed_external_page(embedded_url,prefix,headers,req.form.get('custom_css'))body=soup2xhtml(body,self._cw.encoding)exceptHTTPError,err:body='<h2>%s</h2><h3>%s</h3>'%(_('error while embedding page'),err)rset=self.process_rql()returnself._cw.vreg['views'].main_template(req,self.template,rset=rset,body=body)defentity_has_embedable_url(entity):"""return 1 if the entity provides an allowed embedable url"""url=entity.cw_adapt_to('IEmbedable').embeded_url()ifnoturlornoturl.strip():return0allowed=entity._cw.vreg.config['embed-allowed']ifallowedisNoneornotallowed.match(url):return0return1classEmbedAction(Action):"""display an 'embed' link on entity implementing `embeded_url` method if the returned url match embeding configuration """__regid__='embed'__select__=(one_line_rset()&match_search_state('normal')&adaptable('IEmbedable')&score_entity(entity_has_embedable_url))title=_('embed')defurl(self,row=0):entity=self.cw_rset.get_entity(row,0)url=urljoin(self._cw.base_url(),entity.cw_adapt_to('IEmbedable').embeded_url())ifself._cw.form.has_key('rql'):returnself._cw.build_url('embed',url=url,rql=self._cw.form['rql'])returnself._cw.build_url('embed',url=url)# functions doing necessary substitutions to embed an external html page ######BODY_RGX=re.compile('<body.*?>(.*?)</body>',re.I|re.S|re.U)HREF_RGX=re.compile('<a\s+href="([^"]*)"',re.I|re.S|re.U)SRC_RGX=re.compile('<img\s+src="([^"]*)"',re.I|re.S|re.U)classreplace_href:def__init__(self,prefix,custom_css=None):self.prefix=prefixself.custom_css=custom_cssdef__call__(self,match):original_url=match.group(1)url=self.prefix+urlquote(original_url,safe='')ifself.custom_cssisnotNone:if'?'inurl:url='%s&custom_css=%s'%(url,self.custom_css)else:url='%s?custom_css=%s'%(url,self.custom_css)return'<a href="%s"'%urlclassabsolutize_links:def__init__(self,embedded_url,tag,custom_css=None):self.embedded_url=embedded_urlself.tag=tagself.custom_css=custom_cssdef__call__(self,match):original_url=match.group(1)if'://'inoriginal_url:returnmatch.group(0)# leave it unchangedreturn'%s="%s"'%(self.tag,urljoin(self.embedded_url,original_url))defprefix_links(body,prefix,embedded_url,custom_css=None):filters=((HREF_RGX,absolutize_links(embedded_url,'<a href',custom_css)),(SRC_RGX,absolutize_links(embedded_url,'<img src')),(HREF_RGX,replace_href(prefix,custom_css)))forrgx,replinfilters:body=rgx.sub(repl,body)returnbodydefembed_external_page(url,prefix,headers=None,custom_css=None):req=Request(url,headers=(headersor{}))content=urlopen(req).read()page_source=unicode(content,guess_encoding(content),'replace')page_source=page_sourcematch=BODY_RGX.search(page_source)ifmatchisNone:returnpage_sourcereturnprefix_links(match.group(1),prefix,url,custom_css)