Add an export view dealing with cases where the requested format isn't supported by the profile
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 14 Oct 2016 11:19:02 +0200
changeset 1733 15c2c768d215
parent 1688 0f3d38ffd42d
child 1734 fff22f766b10
Add an export view dealing with cases where the requested format isn't supported by the profile Ensure the UI display a nice message instead of attempting to export to an unsupported format. Related to #15524215
i18n/en.po
i18n/fr.po
test/test_views.py
views/export.py
--- a/i18n/en.po	Tue Oct 11 17:01:55 2016 +0200
+++ b/i18n/en.po	Fri Oct 14 11:19:02 2016 +0200
@@ -103,6 +103,10 @@
 msgid "Entity"
 msgstr ""
 
+#, python-brace-format
+msgid "Export to SEDA version {0} is not possible."
+msgstr ""
+
 msgid ""
 "First level archive unit must have an associated access rule to be "
 "exportable in SEDA 1. You may define it on the archive unit or as a default "
--- a/i18n/fr.po	Tue Oct 11 17:01:55 2016 +0200
+++ b/i18n/fr.po	Fri Oct 14 11:19:02 2016 +0200
@@ -106,6 +106,10 @@
 msgid "Entity"
 msgstr "Entité"
 
+#, python-brace-format
+msgid "Export to SEDA version {0} is not possible."
+msgstr "L'export vers la version {0} du SEDA n'est pas possible sur ce profil."
+
 msgid ""
 "First level archive unit must have an associated access rule to be "
 "exportable in SEDA 1. You may define it on the archive unit or as a default "
--- a/test/test_views.py	Tue Oct 11 17:01:55 2016 +0200
+++ b/test/test_views.py	Fri Oct 14 11:19:02 2016 +0200
@@ -22,6 +22,9 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.web import INTERNAL_FIELD_VALUE
 
+from cubes.seda.views import export
+from cubes.seda.views.export import SEDAExportView, SEDANonSupportedExportView
+
 from testutils import create_transfer_to_bdo, create_archive_unit
 
 
@@ -143,6 +146,47 @@
                          {'novalue_include_rtype': False, 'novalue_label': u'<no value specified>'})
 
 
+class FormatSupportedPredicateTC(CubicWebTC):
+
+    def test_format_supported(self):
+        class fakecls(object):
+            def __init__(self, seda_version):
+                self.seda_version = seda_version
+
+        predicate = export.format_supported()
+
+        with self.admin_access.web_request() as req:
+            transfer = req.create_entity('SEDAArchiveTransfer', title=u'Test widget')
+            req.cnx.commit()
+
+            for seda_version in ('2.0', '1.0', '0.2'):
+                self.assertEqual(predicate(fakecls(seda_version), req, entity=transfer),
+                                 1)
+
+            self.assertEqual(predicate(fakecls(seda_version='1000'), req, entity=transfer),
+                             0)
+
+            with req.cnx.security_enabled(write=False):
+                transfer.cw_set(compat_list=u'SEDA 2.0')
+                req.cnx.commit()
+            transfer.cw_clear_all_caches()
+
+            self.assertEqual(predicate(fakecls(seda_version='2.0'), req, entity=transfer),
+                             1)
+
+            req.form['version'] = '2.0'  # not considered
+            self.assertEqual(predicate(fakecls(seda_version='1.0'), req, entity=transfer),
+                             0)
+
+            req.form['version'] = '2.0'
+            self.assertEqual(predicate(None, req, entity=transfer),
+                             1)
+
+            req.form['version'] = '1.0'
+            self.assertEqual(predicate(None, req, entity=transfer),
+                             0)
+
+
 class ArchiveTransferDiagnoseTabTC(CubicWebTC):
 
     def test_diagnose_tab(self):
@@ -154,5 +198,37 @@
             self.view('seda_at_diagnose_tab', req=req, rset=transfer.as_rset())
 
 
+class ArchiveTransferExportTC(CubicWebTC):
+
+    def test_selected_export_class(self):
+        with self.admin_access.web_request() as req:
+            transfer = req.create_entity('SEDAArchiveTransfer', title=u'diagnosis testing')
+            unit, unit_alt, unit_alt_seq = create_archive_unit(transfer)
+            req.cnx.commit()
+
+            exporter = self.vreg['views'].select('seda.export', req, entity=transfer)
+            self.assertEqual(exporter.__class__, SEDAExportView)
+
+            req.form['version'] = '0.2'
+            exporter = self.vreg['views'].select('seda.export', req, entity=transfer)
+            self.assertEqual(exporter.__class__, SEDAExportView)
+
+            req.form['version'] = '3.0'
+            exporter = self.vreg['views'].select('seda.export', req, entity=transfer)
+            self.assertEqual(exporter.__class__, SEDANonSupportedExportView)
+
+            with req.cnx.security_enabled(write=False):
+                transfer.cw_set(compat_list=u'SEDA 2.0')
+                req.cnx.commit()
+
+            req.form['version'] = '0.2'
+            exporter = self.vreg['views'].select('seda.export', req, entity=transfer)
+            self.assertEqual(exporter.__class__, SEDANonSupportedExportView)
+
+            req.form['version'] = '2.0'
+            exporter = self.vreg['views'].select('seda.export', req, entity=transfer)
+            self.assertEqual(exporter.__class__, SEDAExportView)
+
+
 if __name__ == '__main__':
     unittest.main()
--- a/views/export.py	Tue Oct 11 17:01:55 2016 +0200
+++ b/views/export.py	Fri Oct 14 11:19:02 2016 +0200
@@ -17,7 +17,7 @@
 
 from logilab.common.registry import objectify_predicate
 
-from cubicweb import _
+from cubicweb import view, _
 from cubicweb.predicates import is_instance, one_line_rset
 from cubicweb.web import httpcache, action
 from cubicweb.web.views import idownloadable
@@ -25,9 +25,13 @@
 
 @objectify_predicate
 def format_supported(cls, req, rset=None, entity=None, **kwargs):
+    """Predicate matching cases where an expected format (specified as `version` form param or as a
+    `seda_version` class attribute on the appobject) is supported by the context's transfer entity.
+    """
     if entity is None:
         entity = rset.get_entity(0, 0)
-    return int(('SEDA ' + cls.seda_version) in entity.formats_compat)
+    version = getattr(cls, 'seda_version', req.form.get('version', '2.0'))
+    return int(('SEDA ' + version) in entity.formats_compat)
 
 
 class SEDADownloadAction(action.Action):
@@ -43,7 +47,7 @@
 
     def url(self):
         entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
-        return entity.absolute_url(vid='seda.seda2export',
+        return entity.absolute_url(vid='seda.export',
                                    version=self.seda_version,
                                    format=self.export_format)
 
@@ -104,11 +108,15 @@
     __regid__ = 'seda.export.{0}.{1}'.format(seda_version, export_format)
 
 
-class SEDAExportView(idownloadable.DownloadView):
+class SEDAExportViewMixin(object):
+    __regid__ = 'seda.export'
+    __select__ = one_line_rset() & is_instance('SEDAArchiveTransfer')
+
+
+class SEDAExportView(SEDAExportViewMixin, idownloadable.DownloadView):
     """SEDA archive transfer export view, to download rng, html or xsd representation of a profile.
     """
-    __regid__ = 'seda.seda2export'
-    __select__ = one_line_rset() & is_instance('SEDAArchiveTransfer')
+    __select__ = SEDAExportViewMixin.__select__ & format_supported()
 
     http_cache_manager = httpcache.NoHTTPCacheManager
 
@@ -127,3 +135,18 @@
         entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
         adapter = entity.cw_adapt_to(self.seda_adapter_id)
         self.w(adapter.dump())
+
+
+class SEDANonSupportedExportView(SEDAExportViewMixin, view.EntityView):
+    """SEDA archive transfer export view for cases where an unsupported export is specified.
+    """
+    __select__ = SEDAExportViewMixin.__select__ & ~format_supported()
+
+    def entity_call(self, entity):
+        self.w(u'<p class="bg-error">')
+        version = self._cw.form['version']
+        self.w(self._cw._('Export to SEDA version {0} is not possible.').format(version))
+        self.w(u'</p>')
+        self.w(u'<p>')
+        self.w(self._cw._('Supported formats: {0}.').format(entity.compat_list))
+        self.w(u'</p>')