drop xhtml content-type support (closes #2065651)
* HTMLStream does not care about xml any more
* reqquest.demote_to_html and .xhtml_browser are deprecated
* web config: drop force-html-content-type option
* adjust tests
# copyright 2003-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/>.
"""
Specific views for entities adapting to IDownloadable
=====================================================
"""
__docformat__ = "restructuredtext en"
_ = unicode
from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
from logilab.common.deprecation import class_renamed, deprecated
from cubicweb import tags
from cubicweb.view import EntityView
from cubicweb.predicates import (one_line_rset, is_instance, match_context_prop,
adaptable, has_mimetype)
from cubicweb.mttransforms import ENGINE
from cubicweb.web import component, httpcache
from cubicweb.web.views import primary, baseviews
@deprecated('[3.10] use a custom IDownloadable adapter instead')
def download_box(w, entity, title=None, label=None, footer=u''):
req = entity._cw
w(u'<div class="sideBox">')
if title is None:
title = req._('download')
w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>'
% xml_escape(title))
w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
% (xml_escape(entity.cw_adapt_to('IDownloadable').download_url()),
req.uiprops['DOWNLOAD_ICON'],
req._('download icon'), xml_escape(label or entity.dc_title())))
w(u'%s</div>' % footer)
w(u'</div></div>\n')
class DownloadBox(component.EntityCtxComponent):
"""add download box"""
__regid__ = 'download_box' # no download box for images
__select__ = (component.EntityCtxComponent.__select__ &
adaptable('IDownloadable') & ~has_mimetype('image/'))
order = 10
title = _('download')
def init_rendering(self):
self.items = [self.entity]
def render_body(self, w):
for item in self.items:
idownloadable = item.cw_adapt_to('IDownloadable')
w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
% (xml_escape(idownloadable.download_url()),
self._cw.uiprops['DOWNLOAD_ICON'],
self._cw._('download icon'),
xml_escape(idownloadable.download_file_name())))
class DownloadView(EntityView):
"""download view
this view is replacing the deprecated 'download' controller and allow
downloading of entities providing the necessary interface
"""
__regid__ = 'download'
__select__ = one_line_rset() & adaptable('IDownloadable')
templatable = False
content_type = 'application/octet-stream'
binary = True
http_cache_manager = httpcache.EntityHTTPCacheManager
add_to_breadcrumbs = False
def set_request_content_type(self):
"""overriden to set the correct filetype and filename"""
entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
adapter = entity.cw_adapt_to('IDownloadable')
encoding = adapter.download_encoding()
if encoding in BINARY_ENCODINGS:
contenttype = 'application/%s' % encoding
encoding = None
else:
contenttype = adapter.download_content_type()
self._cw.set_content_type(contenttype or self.content_type,
filename=adapter.download_file_name(),
encoding=encoding,
disposition='attachment')
def call(self):
entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
adapter = entity.cw_adapt_to('IDownloadable')
self.w(adapter.download_data())
def last_modified(self):
return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).modification_date
class DownloadLinkView(EntityView):
"""view displaying a link to download the file"""
__regid__ = 'downloadlink'
__select__ = adaptable('IDownloadable')
title = None # should not be listed in possible views
def cell_call(self, row, col, title=None, **kwargs):
entity = self.cw_rset.get_entity(row, col)
url = xml_escape(entity.cw_adapt_to('IDownloadable').download_url())
self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
class IDownloadablePrimaryView(primary.PrimaryView):
__select__ = adaptable('IDownloadable')
def render_entity_attributes(self, entity):
self.w(u'<div class="content">')
adapter = entity.cw_adapt_to('IDownloadable')
contenttype = adapter.download_content_type()
if contenttype.startswith('image/'):
self._cw.add_js('cubicweb.image.js')
self.wview('image', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
link=True, klass='contentimage')
super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
elif contenttype.endswith('html'):
self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
self.wview('ehtml', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
height='600px', width='100%')
else:
super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
self.render_data(entity, contenttype, 'text/html')
self.w(u'</div>')
def render_data(self, entity, sourcemt, targetmt):
adapter = entity.cw_adapt_to('IDownloadable')
if ENGINE.find_path(sourcemt, targetmt):
try:
self.w(entity._cw_mtc_transform(adapter.download_data(), sourcemt,
targetmt, adapter.download_encoding()))
except Exception as ex:
self.exception('while rendering data for %s', entity)
msg = self._cw._("can't display data, unexpected error: %s") \
% xml_escape(unicode(ex))
self.w('<div class="error">%s</div>' % msg)
return True
return False
class IDownloadableOneLineView(baseviews.OneLineView):
__select__ = adaptable('IDownloadable')
def cell_call(self, row, col, title=None, **kwargs):
"""the oneline view is a link to download the file"""
entity = self.cw_rset.get_entity(row, col)
url = xml_escape(entity.absolute_url())
adapter = entity.cw_adapt_to('IDownloadable')
name = xml_escape(title or entity.dc_title())
durl = xml_escape(adapter.download_url())
self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
(url, name, durl, self._cw._('download')))
IDownloadableLineView = class_renamed(
'IDownloadableLineView', IDownloadableOneLineView,
'[3.10] IDownloadableLineView is deprecated, use IDownloadableOneLineView')
class AbstractEmbeddedView(EntityView):
__abstract__ = True
_embedding_tag = None
def call(self, **kwargs):
rset = self.cw_rset
for i in xrange(len(rset)):
self.w(u'<div class="efile">')
self.wview(self.__regid__, rset, row=i, col=0, **kwargs)
self.w(u'</div>')
def cell_call(self, row, col, link=False, **kwargs):
entity = self.cw_rset.get_entity(row, col)
adapter = entity.cw_adapt_to('IDownloadable')
tag = self._embedding_tag(src=adapter.download_url(), # pylint: disable=E1102
alt=(self._cw._('download %s') % adapter.download_file_name()),
**kwargs)
if link:
self.w(u'<a href="%s">%s</a>' % (adapter.download_url(), tag))
else:
self.w(tag)
class ImageView(AbstractEmbeddedView):
"""image embedded view"""
__regid__ = 'image'
__select__ = has_mimetype('image/')
title = _('image')
_embedding_tag = tags.img
class EHTMLView(AbstractEmbeddedView):
"""html embedded view"""
__regid__ = 'ehtml'
__select__ = has_mimetype('text/html')
title = _('embedded html')
_embedding_tag = tags.iframe