web/views/idownloadable.py
changeset 5556 9ab2b4c74baf
parent 5467 57372dbfd114
child 5714 04a8e48f10bc
equal deleted inserted replaced
5555:a64f48dd5fe4 5556:9ab2b4c74baf
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    14 # details.
    14 # details.
    15 #
    15 #
    16 # You should have received a copy of the GNU Lesser General Public License along
    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/>.
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    18 """Specific views for entities implementing IDownloadable
    18 """Specific views for entities adapting to IDownloadable"""
    19 
    19 
    20 """
       
    21 __docformat__ = "restructuredtext en"
    20 __docformat__ = "restructuredtext en"
    22 _ = unicode
    21 _ = unicode
    23 
    22 
    24 from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
    23 from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
    25 
    24 
    26 from cubicweb.view import EntityView
    25 from cubicweb.view import EntityView
    27 from cubicweb.selectors import (one_line_rset, score_entity,
    26 from cubicweb.selectors import (one_line_rset, implements, match_context_prop,
    28                                 implements, match_context_prop)
    27                                 adaptable, has_mimetype)
    29 from cubicweb.interfaces import IDownloadable
       
    30 from cubicweb.mttransforms import ENGINE
    28 from cubicweb.mttransforms import ENGINE
    31 from cubicweb.web.box import EntityBoxTemplate
    29 from cubicweb.web.box import EntityBoxTemplate
    32 from cubicweb.web.views import primary, baseviews
    30 from cubicweb.web.views import primary, baseviews
    33 
    31 
    34 
       
    35 def is_image(entity):
       
    36     mt = entity.download_content_type()
       
    37     if not (mt and mt.startswith('image/')):
       
    38         return 0
       
    39     return 1
       
    40 
    32 
    41 def download_box(w, entity, title=None, label=None, footer=u''):
    33 def download_box(w, entity, title=None, label=None, footer=u''):
    42     req = entity._cw
    34     req = entity._cw
    43     w(u'<div class="sideBox">')
    35     w(u'<div class="sideBox">')
    44     if title is None:
    36     if title is None:
    45         title = req._('download')
    37         title = req._('download')
    46     w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>'
    38     w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>'
    47       % xml_escape(title))
    39       % xml_escape(title))
    48     w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
    40     w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
    49     w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
    41     w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
    50       % (xml_escape(entity.download_url()),
    42       % (xml_escape(entity.cw_adapt_to('IDownloadable').download_url()),
    51          req.uiprops['DOWNLOAD_ICON'],
    43          req.uiprops['DOWNLOAD_ICON'],
    52          _('download icon'), xml_escape(label or entity.dc_title())))
    44          _('download icon'), xml_escape(label or entity.dc_title())))
    53     w(u'%s</div>' % footer)
    45     w(u'%s</div>' % footer)
    54     w(u'</div></div>\n')
    46     w(u'</div></div>\n')
    55 
    47 
    56 
    48 
    57 class DownloadBox(EntityBoxTemplate):
    49 class DownloadBox(EntityBoxTemplate):
    58     __regid__ = 'download_box'
    50     __regid__ = 'download_box'
    59     # no download box for images
    51     # no download box for images
    60     # XXX primary_view selector ?
    52     # XXX primary_view selector ?
    61     __select__ = (one_line_rset() & implements(IDownloadable) &
    53     __select__ = (one_line_rset() & match_context_prop()
    62                   match_context_prop() & ~score_entity(is_image))
    54                   & adaptable('IDownloadable') & ~has_mimetype('image/'))
    63     order = 10
    55     order = 10
    64 
    56 
    65     def cell_call(self, row, col, title=None, label=None, **kwargs):
    57     def cell_call(self, row, col, title=None, label=None, **kwargs):
    66         entity = self.cw_rset.get_entity(row, col)
    58         entity = self.cw_rset.get_entity(row, col)
    67         download_box(self.w, entity, title, label)
    59         download_box(self.w, entity, title, label)
    70 class DownloadView(EntityView):
    62 class DownloadView(EntityView):
    71     """this view is replacing the deprecated 'download' controller and allow
    63     """this view is replacing the deprecated 'download' controller and allow
    72     downloading of entities providing the necessary interface
    64     downloading of entities providing the necessary interface
    73     """
    65     """
    74     __regid__ = 'download'
    66     __regid__ = 'download'
    75     __select__ = one_line_rset() & implements(IDownloadable)
    67     __select__ = one_line_rset() & adaptable('IDownloadable')
    76 
    68 
    77     templatable = False
    69     templatable = False
    78     content_type = 'application/octet-stream'
    70     content_type = 'application/octet-stream'
    79     binary = True
    71     binary = True
    80     add_to_breadcrumbs = False
    72     add_to_breadcrumbs = False
    81 
    73 
    82     def set_request_content_type(self):
    74     def set_request_content_type(self):
    83         """overriden to set the correct filetype and filename"""
    75         """overriden to set the correct filetype and filename"""
    84         entity = self.cw_rset.complete_entity(0, 0)
    76         entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
    85         encoding = entity.download_encoding()
    77         adapter = entity.cw_adapt_to('IDownloadable')
       
    78         encoding = adapter.download_encoding()
    86         if encoding in BINARY_ENCODINGS:
    79         if encoding in BINARY_ENCODINGS:
    87             contenttype = 'application/%s' % encoding
    80             contenttype = 'application/%s' % encoding
    88             encoding = None
    81             encoding = None
    89         else:
    82         else:
    90             contenttype = entity.download_content_type()
    83             contenttype = adapter.download_content_type()
    91         self._cw.set_content_type(contenttype or self.content_type,
    84         self._cw.set_content_type(contenttype or self.content_type,
    92                                   filename=entity.download_file_name(),
    85                                   filename=adapter.download_file_name(),
    93                                   encoding=encoding)
    86                                   encoding=encoding)
    94 
    87 
    95     def call(self):
    88     def call(self):
    96         self.w(self.cw_rset.complete_entity(0, 0).download_data())
    89         entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0)
       
    90         adapter = entity.cw_adapt_to('IDownloadable')
       
    91         self.w(adapter.download_data())
    97 
    92 
    98 
    93 
    99 class DownloadLinkView(EntityView):
    94 class DownloadLinkView(EntityView):
   100     """view displaying a link to download the file"""
    95     """view displaying a link to download the file"""
   101     __regid__ = 'downloadlink'
    96     __regid__ = 'downloadlink'
   102     __select__ = implements(IDownloadable)
    97     __select__ = adaptable('IDownloadable')
   103     title = None # should not be listed in possible views
    98     title = None # should not be listed in possible views
   104 
    99 
   105 
   100 
   106     def cell_call(self, row, col, title=None, **kwargs):
   101     def cell_call(self, row, col, title=None, **kwargs):
   107         entity = self.cw_rset.get_entity(row, col)
   102         entity = self.cw_rset.get_entity(row, col)
   108         url = xml_escape(entity.download_url())
   103         url = xml_escape(entity.cw_adapt_to('IDownloadable').download_url())
   109         self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
   104         self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
   110 
   105 
   111 
   106 
   112 class IDownloadablePrimaryView(primary.PrimaryView):
   107 class IDownloadablePrimaryView(primary.PrimaryView):
   113     __select__ = implements(IDownloadable)
   108     __select__ = adaptable('IDownloadable')
   114 
   109 
   115     def render_entity_attributes(self, entity):
   110     def render_entity_attributes(self, entity):
   116         super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
   111         super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
   117         self.w(u'<div class="content">')
   112         self.w(u'<div class="content">')
   118         contenttype = entity.download_content_type()
   113         adapter = entity.cw_adapt_to('IDownloadable')
       
   114         contenttype = adapter.download_content_type()
   119         if contenttype.startswith('image/'):
   115         if contenttype.startswith('image/'):
   120             self.wview('image', entity.cw_rset, row=entity.cw_row)
   116             self.wview('image', entity.cw_rset, row=entity.cw_row)
   121         else:
   117         else:
   122             self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
   118             self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
   123             try:
   119             try:
   124                 if ENGINE.has_input(contenttype):
   120                 if ENGINE.has_input(contenttype):
       
   121                     # XXX expect File like schema (access to 'data' attribute)
   125                     self.w(entity.printable_value('data'))
   122                     self.w(entity.printable_value('data'))
   126             except TransformError:
   123             except TransformError:
   127                 pass
   124                 pass
   128             except Exception, ex:
   125             except Exception, ex:
   129                 msg = self._cw._("can't display data, unexpected error: %s") \
   126                 msg = self._cw._("can't display data, unexpected error: %s") \
   131                 self.w('<div class="error">%s</div>' % msg)
   128                 self.w('<div class="error">%s</div>' % msg)
   132         self.w(u'</div>')
   129         self.w(u'</div>')
   133 
   130 
   134 
   131 
   135 class IDownloadableLineView(baseviews.OneLineView):
   132 class IDownloadableLineView(baseviews.OneLineView):
   136     __select__ = implements(IDownloadable)
   133     __select__ = adaptable('IDownloadable')
   137 
   134 
   138     def cell_call(self, row, col, title=None, **kwargs):
   135     def cell_call(self, row, col, title=None, **kwargs):
   139         """the oneline view is a link to download the file"""
   136         """the oneline view is a link to download the file"""
   140         entity = self.cw_rset.get_entity(row, col)
   137         entity = self.cw_rset.get_entity(row, col)
   141         url = xml_escape(entity.absolute_url())
   138         url = xml_escape(entity.absolute_url())
   142         name = xml_escape(title or entity.download_file_name())
   139         adapter = entity.cw_adapt_to('IDownloadable')
   143         durl = xml_escape(entity.download_url())
   140         name = xml_escape(title or adapter.download_file_name())
       
   141         durl = xml_escape(adapter.download_url())
   144         self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
   142         self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
   145                (url, name, durl, self._cw._('download')))
   143                (url, name, durl, self._cw._('download')))
   146 
   144 
   147 
   145 
   148 class ImageView(EntityView):
   146 class ImageView(EntityView):
   149     __regid__ = 'image'
   147     __regid__ = 'image'
   150     __select__ = implements(IDownloadable) & score_entity(is_image)
   148     __select__ = has_mimetype('image/')
   151 
   149 
   152     title = _('image')
   150     title = _('image')
   153 
   151 
   154     def call(self):
   152     def call(self):
   155         rset = self.cw_rset
   153         rset = self.cw_rset
   158             self.wview(self.__regid__, rset, row=i, col=0)
   156             self.wview(self.__regid__, rset, row=i, col=0)
   159             self.w(u'</div>')
   157             self.w(u'</div>')
   160 
   158 
   161     def cell_call(self, row, col, width=None, height=None, link=False):
   159     def cell_call(self, row, col, width=None, height=None, link=False):
   162         entity = self.cw_rset.get_entity(row, col)
   160         entity = self.cw_rset.get_entity(row, col)
       
   161         adapter = entity.cw_adapt_to('IDownloadable')
   163         #if entity.data_format.startswith('image/'):
   162         #if entity.data_format.startswith('image/'):
   164         imgtag = u'<img src="%s" alt="%s" ' % (
   163         imgtag = u'<img src="%s" alt="%s" ' % (
   165             xml_escape(entity.download_url()),
   164             xml_escape(adapter.download_url()),
   166             (self._cw._('download %s')  % xml_escape(entity.download_file_name())))
   165             (self._cw._('download %s')  % xml_escape(adapter.download_file_name())))
   167         if width:
   166         if width:
   168             imgtag += u'width="%i" ' % width
   167             imgtag += u'width="%i" ' % width
   169         if height:
   168         if height:
   170             imgtag += u'height="%i" ' % height
   169             imgtag += u'height="%i" ' % height
   171         imgtag += u'/>'
   170         imgtag += u'/>'