cubicweb/web/views/idownloadable.py
changeset 11057 0b59724cb3f2
parent 10907 9ae707db5265
child 11767 432f87a63057
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
       
     1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """
       
    19 Specific views for entities adapting to IDownloadable
       
    20 =====================================================
       
    21 """
       
    22 __docformat__ = "restructuredtext en"
       
    23 from cubicweb import _
       
    24 
       
    25 from six.moves import range
       
    26 
       
    27 from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
       
    28 from logilab.common.deprecation import class_renamed, deprecated
       
    29 
       
    30 from cubicweb import tags
       
    31 from cubicweb.view import EntityView
       
    32 from cubicweb.predicates import (one_line_rset, is_instance, match_context_prop,
       
    33                                  adaptable, has_mimetype)
       
    34 from cubicweb.mttransforms import ENGINE
       
    35 from cubicweb.web import component, httpcache
       
    36 from cubicweb.web.views import primary, baseviews
       
    37 
       
    38 
       
    39 class DownloadBox(component.EntityCtxComponent):
       
    40     """add download box"""
       
    41     __regid__ = 'download_box'    # no download box for images
       
    42     __select__ = (component.EntityCtxComponent.__select__ &
       
    43                   adaptable('IDownloadable') & ~has_mimetype('image/'))
       
    44 
       
    45     order = 10
       
    46     title = _('download')
       
    47 
       
    48     def init_rendering(self):
       
    49         self.items = [self.entity]
       
    50 
       
    51     def render_body(self, w):
       
    52         for item in self.items:
       
    53             idownloadable = item.cw_adapt_to('IDownloadable')
       
    54             w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
       
    55               % (xml_escape(idownloadable.download_url()),
       
    56                  self._cw.uiprops['DOWNLOAD_ICON'],
       
    57                  self._cw._('download icon'),
       
    58                  xml_escape(idownloadable.download_file_name())))
       
    59 
       
    60 
       
    61 class DownloadView(EntityView):
       
    62     """download view
       
    63 
       
    64     this view is replacing the deprecated 'download' controller and allow
       
    65     downloading of entities providing the necessary interface
       
    66     """
       
    67     __regid__ = 'download'
       
    68     __select__ = one_line_rset() & adaptable('IDownloadable')
       
    69 
       
    70     templatable = False
       
    71     content_type = 'application/octet-stream'
       
    72     binary = True
       
    73     http_cache_manager = httpcache.EntityHTTPCacheManager
       
    74     add_to_breadcrumbs = False
       
    75 
       
    76     def set_request_content_type(self):
       
    77         """overriden to set the correct filetype and filename"""
       
    78         entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
       
    79         adapter = entity.cw_adapt_to('IDownloadable')
       
    80         encoding = adapter.download_encoding()
       
    81         if encoding in BINARY_ENCODINGS:
       
    82             contenttype = 'application/%s' % encoding
       
    83             encoding = None
       
    84         else:
       
    85             contenttype = adapter.download_content_type()
       
    86         self._cw.set_content_type(contenttype or self.content_type,
       
    87                                   filename=adapter.download_file_name(),
       
    88                                   encoding=encoding,
       
    89                                   disposition='attachment')
       
    90 
       
    91     def call(self):
       
    92         entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
       
    93         adapter = entity.cw_adapt_to('IDownloadable')
       
    94         self.w(adapter.download_data())
       
    95 
       
    96     def last_modified(self):
       
    97         return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).modification_date
       
    98 
       
    99 
       
   100 class DownloadLinkView(EntityView):
       
   101     """view displaying a link to download the file"""
       
   102     __regid__ = 'downloadlink'
       
   103     __select__ = adaptable('IDownloadable')
       
   104     title = None # should not be listed in possible views
       
   105 
       
   106 
       
   107     def cell_call(self, row, col, title=None, **kwargs):
       
   108         entity = self.cw_rset.get_entity(row, col)
       
   109         url = xml_escape(entity.cw_adapt_to('IDownloadable').download_url())
       
   110         self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
       
   111 
       
   112 
       
   113 class IDownloadablePrimaryView(primary.PrimaryView):
       
   114     __select__ = adaptable('IDownloadable')
       
   115 
       
   116     def render_entity_attributes(self, entity):
       
   117         self.w(u'<div class="content">')
       
   118         adapter = entity.cw_adapt_to('IDownloadable')
       
   119         contenttype = adapter.download_content_type()
       
   120         if contenttype.startswith('image/'):
       
   121             self._cw.add_js('cubicweb.image.js')
       
   122             self.wview('image', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
       
   123                        link=True, klass='contentimage')
       
   124             super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
       
   125         elif contenttype.endswith('html'):
       
   126             self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
       
   127             self.wview('ehtml', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
       
   128                        height='600px', width='100%')
       
   129         else:
       
   130             super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
       
   131             self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
       
   132             self.render_data(entity, contenttype, 'text/html')
       
   133         self.w(u'</div>')
       
   134 
       
   135     def render_data(self, entity, sourcemt, targetmt):
       
   136         adapter = entity.cw_adapt_to('IDownloadable')
       
   137         if ENGINE.find_path(sourcemt, targetmt):
       
   138             try:
       
   139                 self.w(entity._cw_mtc_transform(adapter.download_data(), sourcemt,
       
   140                                                 targetmt, adapter.download_encoding()))
       
   141             except Exception as ex:
       
   142                 self.exception('while rendering data for %s', entity)
       
   143                 msg = self._cw._("can't display data, unexpected error: %s") \
       
   144                       % xml_escape(unicode(ex))
       
   145                 self.w('<div class="error">%s</div>' % msg)
       
   146             return True
       
   147         return False
       
   148 
       
   149 
       
   150 class IDownloadableOneLineView(baseviews.OneLineView):
       
   151     __select__ = adaptable('IDownloadable')
       
   152 
       
   153     def cell_call(self, row, col, title=None, **kwargs):
       
   154         """the oneline view is a link to download the file"""
       
   155         entity = self.cw_rset.get_entity(row, col)
       
   156         url = xml_escape(entity.absolute_url())
       
   157         adapter = entity.cw_adapt_to('IDownloadable')
       
   158         name = xml_escape(title or entity.dc_title())
       
   159         durl = xml_escape(adapter.download_url())
       
   160         self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
       
   161                (url, name, durl, self._cw._('download')))
       
   162 
       
   163 
       
   164 class AbstractEmbeddedView(EntityView):
       
   165     __abstract__ = True
       
   166 
       
   167     _embedding_tag = None
       
   168 
       
   169     def call(self, **kwargs):
       
   170         rset = self.cw_rset
       
   171         for i in range(len(rset)):
       
   172             self.w(u'<div class="efile">')
       
   173             self.wview(self.__regid__, rset, row=i, col=0, **kwargs)
       
   174             self.w(u'</div>')
       
   175 
       
   176     def cell_call(self, row, col, link=False, **kwargs):
       
   177         entity = self.cw_rset.get_entity(row, col)
       
   178         adapter = entity.cw_adapt_to('IDownloadable')
       
   179         tag = self._embedding_tag(src=adapter.download_url(), # pylint: disable=E1102
       
   180                                   alt=(self._cw._('download %s') % adapter.download_file_name()),
       
   181                                   **kwargs)
       
   182         if link:
       
   183             self.w(u'<a href="%s">%s</a>' % (adapter.download_url(), tag))
       
   184         else:
       
   185             self.w(tag)
       
   186 
       
   187 
       
   188 class ImageView(AbstractEmbeddedView):
       
   189     """image embedded view"""
       
   190     __regid__ = 'image'
       
   191     __select__ = has_mimetype('image/')
       
   192 
       
   193     title = _('image')
       
   194     _embedding_tag = tags.img
       
   195 
       
   196 
       
   197 class EHTMLView(AbstractEmbeddedView):
       
   198     """html embedded view"""
       
   199     __regid__ = 'ehtml'
       
   200     __select__ = has_mimetype('text/html')
       
   201 
       
   202     title = _('embedded html')
       
   203     _embedding_tag = tags.iframe