# copyright 2003-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/>."""base xml and rss views"""__docformat__="restructuredtext en"_=unicodefrombase64importb64encodefromtimeimporttimezonefromlogilab.mtconverterimportxml_escapefromcubicweb.predicatesimport(is_instance,non_final_entity,one_line_rset,appobject_selectable,adaptable)fromcubicweb.viewimportEntityView,EntityAdapter,AnyRsetView,Componentfromcubicweb.viewimportimplements_adapter_compatfromcubicweb.uilibimportsimple_sgml_tagfromcubicweb.webimporthttpcache,componentdefencode_bytes(value):return'<![CDATA[%s]]>'%b64encode(value.getvalue())# see cubicweb.sobjects.parser.DEFAULT_CONVERTERSSERIALIZERS={'String':xml_escape,'Bytes':encode_bytes,'Date':lambdax:x.strftime('%Y-%m-%d'),'Datetime':lambdax:x.strftime('%Y-%m-%d %H:%M:%S'),'Time':lambdax:x.strftime('%H:%M:%S'),'TZDatetime':lambdax:x.strftime('%Y-%m-%d %H:%M:%S'),# XXX TZ'TZTime':lambdax:x.strftime('%H:%M:%S'),'Interval':lambdax:x.days*60*60*24+x.seconds,}# base xml views ##############################################################classXMLView(EntityView):"""xml view for entities"""__regid__='xml'title=_('xml export (entities)')templatable=Falsecontent_type='text/xml'xml_root='rset'item_vid='xmlitem'defcell_call(self,row,col):self.wview(self.item_vid,self.cw_rset,row=row,col=col)defcall(self):"""display a list of entities by calling their <item_vid> view"""self.w(u'<?xml version="1.0" encoding="%s"?>\n'%self._cw.encoding)self.w(u'<%s size="%s">\n'%(self.xml_root,len(self.cw_rset)))foriinxrange(self.cw_rset.rowcount):self.cell_call(i,0)self.w(u'</%s>\n'%self.xml_root)classXMLItemView(EntityView):__regid__='xmlitem'defentity_call(self,entity):"""element as an item for an xml feed"""entity.complete()source=entity.cw_metainformation()['source']['uri']self.w(u'<%s eid="%s" cwuri="%s" cwsource="%s">\n'%(entity.__regid__,entity.eid,xml_escape(entity.cwuri),xml_escape(source)))forrschema,attrschemainentity.e_schema.attribute_definitions():attr=rschema.typeifattrin('eid','cwuri'):continueelse:try:value=entity.cw_attr_cache[attr]exceptKeyError:# BytescontinueifvalueisNone:self.w(u' <%s/>\n'%attr)else:try:value=SERIALIZERS[attrschema](value)exceptKeyError:passself.w(u' <%s>%s</%s>\n'%(attr,value,attr))forrelstrinself._cw.list_form_param('relation'):try:rtype,role=relstr.split('-')exceptValueError:self.error('badly formated relation name %r',relstr)continueifrole=='subject':getrschema=entity.e_schema.subjrelselifrole=='object':getrschema=entity.e_schema.objrelselse:self.error('badly formated relation name %r',relstr)continueifnotrtypeingetrschema:self.error('unexisting relation %r',relstr)continueself.w(u' <%s role="%s">\n'%(rtype,role))self.wview('xmlrelateditem',entity.related(rtype,role,safe=True),'null')self.w(u' </%s>\n'%rtype)self.w(u'</%s>\n'%(entity.e_schema))classXMLRelatedItemView(EntityView):__regid__='xmlrelateditem'add_div_section=Falsedefentity_call(self,entity):# XXX put unique attributes as xml attribute, they are much probably# used to search existing entities in client data feed, and putting it# here may avoid an extra request to get those attributes valuesself.w(u' <%s eid="%s" cwuri="%s"/>\n'%(entity.e_schema,entity.eid,xml_escape(entity.cwuri)))classXMLRelatedItemStateView(XMLRelatedItemView):__select__=is_instance('State')defentity_call(self,entity):self.w(u' <%s eid="%s" cwuri="%s" name="%s"/>\n'%(entity.e_schema,entity.eid,xml_escape(entity.cwuri),xml_escape(entity.name)))classXMLRsetView(AnyRsetView):"""dumps raw rset as xml"""__regid__='rsetxml'title=_('xml export')templatable=Falsecontent_type='text/xml'xml_root='rset'defcall(self):w=self.wrset,descr=self.cw_rset,self.cw_rset.descriptioneschema=self._cw.vreg.schema.eschemalabels=self.columns_labels(tr=False)w(u'<?xml version="1.0" encoding="%s"?>\n'%self._cw.encoding)w(u'<%s query="%s">\n'%(self.xml_root,xml_escape(rset.printable_rql())))forrowindex,rowinenumerate(self.cw_rset):w(u' <row>\n')forcolindex,valinenumerate(row):etype=descr[rowindex][colindex]tag=labels[colindex]attrs={}if'('intag:attrs['expr']=tagtag='funccall'ifvalisnotNoneandnoteschema(etype).final:attrs['eid']=val# csvrow.append(val) # val is eid in that caseval=self._cw.view('textincontext',rset,row=rowindex,col=colindex)else:val=self._cw.view('final',rset,row=rowindex,col=colindex,format='text/plain')w(simple_sgml_tag(tag,val,**attrs))w(u' </row>\n')w(u'</%s>\n'%self.xml_root)# RSS stuff ###################################################################classIFeedAdapter(EntityAdapter):__needs_bw_compat__=True__regid__='IFeed'__select__=is_instance('Any')@implements_adapter_compat('IFeed')defrss_feed_url(self):"""return an url to the rss feed for this entity"""returnself.entity.absolute_url(vid='rss')classRSSFeedURL(Component):__regid__='rss_feed_url'__select__=non_final_entity()deffeed_url(self):returnself._cw.build_url(rql=self.cw_rset.limited_rql(),vid='rss')classRSSEntityFeedURL(Component):__regid__='rss_feed_url'__select__=one_line_rset()&adaptable('IFeed')deffeed_url(self):entity=self.cw_rset.get_entity(self.cw_rowor0,self.cw_color0)returnentity.cw_adapt_to('IFeed').rss_feed_url()classRSSIconBox(component.CtxComponent):"""just display the RSS icon on uniform result set"""__regid__='rss'__select__=(component.CtxComponent.__select__&appobject_selectable('components','rss_feed_url'))visible=Falseorder=999defrender(self,w,**kwargs):try:rss=self._cw.uiprops['RSS_LOGO']exceptKeyError:self.error('missing RSS_LOGO external resource')returnurlgetter=self._cw.vreg['components'].select('rss_feed_url',self._cw,rset=self.cw_rset)url=urlgetter.feed_url()w(u'<a href="%s"><img src="%s" alt="rss"/></a>\n'%(xml_escape(url),rss))classRSSView(XMLView):__regid__='rss'title=_('rss export')templatable=Falsecontent_type='text/xml'http_cache_manager=httpcache.MaxAgeHTTPCacheManagercache_max_age=60*60*2# stay in http cache for 2 hours by defaultitem_vid='rssitem'def_open(self):req=self._cwself.w(u'<?xml version="1.0" encoding="%s"?>\n'%req.encoding)self.w(u'<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n')self.w(u' <channel>\n')self.w(u' <title>%s RSS Feed</title>\n'%xml_escape(self.page_title()))self.w(u' <description>%s</description>\n'%xml_escape(req.form.get('vtitle','')))params=req.form.copy()params.pop('vid',None)self.w(u' <link>%s</link>\n'%xml_escape(self._cw.build_url(**params)))def_close(self):self.w(u' </channel>\n')self.w(u'</rss>')defcall(self):"""display a list of entities by calling their <item_vid> view"""self._open()foriinxrange(self.cw_rset.rowcount):self.cell_call(i,0)self._close()defcell_call(self,row,col):self.wview(self.item_vid,self.cw_rset,row=row,col=col)classRSSItemView(EntityView):__regid__='rssitem'date_format='%%Y-%%m-%%dT%%H:%%M%+03i:00'%(timezone/3600)add_div_section=Falsedefcell_call(self,row,col):entity=self.cw_rset.complete_entity(row,col)self.w(u'<item>\n')self.w(u'<guid isPermaLink="true">%s</guid>\n'%xml_escape(entity.absolute_url()))self.render_title_link(entity)self.render_description(entity)self._marker('dc:date',entity.dc_date(self.date_format))self.render_entity_creator(entity)self.w(u'</item>\n')defrender_description(self,entity):self._marker('description',entity.dc_description(format='text/html'))defrender_title_link(self,entity):self._marker('title',entity.dc_long_title())self._marker('link',entity.absolute_url())defrender_entity_creator(self,entity):ifentity.creator:self._marker('dc:creator',entity.dc_creator())def_marker(self,marker,value):ifvalue:self.w(u' <%s>%s</%s>\n'%(marker,xml_escape(value),marker))