# copyright 2003-2024 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact https://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 <https://www.gnu.org/licenses/>.
"""
Specific views for entities adapting to IDownloadable
=====================================================
"""
from logilab.mtconverter import BINARY_ENCODINGS, xml_escape
from cubicweb import _
from cubicweb import tags
from cubicweb.mttransforms import ENGINE
from cubicweb.predicates import (
one_line_rset,
adaptable,
has_mimetype,
)
from cubicweb_web.view import EntityView
from cubicweb_web import component, httpcache
from cubicweb_web.views import primary, baseviews
[docs]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(
'<a href="%s"><img src="%s" alt="%s"/> %s</a>',
idownloadable.download_url(),
self._cw.uiprops["DOWNLOAD_ICON"],
self._cw._("download icon"),
idownloadable.download_file_name(),
)
[docs]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
[docs]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 = entity.cw_adapt_to("IDownloadable").download_url()
self.w('<a href="%s">%s</a>', url, title or entity.dc_title())
[docs]class IDownloadablePrimaryView(primary.PrimaryView):
__select__ = adaptable("IDownloadable")
def render_entity_attributes(self, entity):
self.w('<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("</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(str(ex))
self.w('<div class="error">%s</div>', msg)
return True
return False
[docs]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 = entity.absolute_url()
adapter = entity.cw_adapt_to("IDownloadable")
name = title or entity.dc_title()
durl = adapter.download_url()
self.w(
'<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('<div class="efile">')
self.wview(self.__regid__, rset, row=i, col=0, **kwargs)
self.w("</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('<a href="%s">%s</a>', adapter.download_url(), tag, escape=False)
else:
self.w(tag)
[docs]class ImageView(AbstractEmbeddedView):
"""image embedded view"""
__regid__ = "image"
__select__ = has_mimetype("image/")
title = _("image")
_embedding_tag = tags.img
[docs]class EHTMLView(AbstractEmbeddedView):
"""html embedded view"""
__regid__ = "ehtml"
__select__ = has_mimetype("text/html")
title = _("embedded html")
_embedding_tag = tags.iframe