cubicweb/web/views/idownloadable.py
changeset 11057 0b59724cb3f2
parent 10907 9ae707db5265
child 11767 432f87a63057
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/views/idownloadable.py	Sat Jan 16 13:48:51 2016 +0100
@@ -0,0 +1,203 @@
+# copyright 2003-2014 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"
+from cubicweb import _
+
+from six.moves import range
+
+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
+
+
+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')))
+
+
+class AbstractEmbeddedView(EntityView):
+    __abstract__ = True
+
+    _embedding_tag = None
+
+    def call(self, **kwargs):
+        rset = self.cw_rset
+        for i in range(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