# HG changeset patch # User Sylvain Thénault # Date 1437393354 -7200 # Node ID bc2f6f0d74331cb31f3ff054850ba15251aca699 # Parent 7846d26ff91de1550fba11db801c578f6bad18dd [urlpublish] RESTPathEvaluator now use vid_from_rset This avoid cases where vid may be unexpectedly overwritten. For instance when you define a custom vid for a mime type in VID_BY_MIMETYPE, it will currently be overriden by the URL publisher when you access to / with the proper Accept header. To do so, a new 'check_table' argument is introduced, which may cause bw compatibility problems if the function has been monkey-patched. Also pep8 a bit the tests. Closes #5705835 diff -r 7846d26ff91d -r bc2f6f0d7433 web/test/unittest_urlpublisher.py --- a/web/test/unittest_urlpublisher.py Fri Jul 24 16:19:39 2015 +0200 +++ b/web/test/unittest_urlpublisher.py Mon Jul 20 13:55:54 2015 +0200 @@ -25,7 +25,7 @@ from cubicweb.rset import ResultSet from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.fake import FakeRequest -from cubicweb.web import NotFound, Redirect +from cubicweb.web import NotFound, Redirect, views from cubicweb.web.views.urlrewrite import SimpleReqRewriter @@ -69,6 +69,7 @@ self.assertEqual("Any X,AA,AB ORDERBY AB WHERE X is_instance_of CWEType, " "X modification_date AA, X name AB", rset.printable_rql()) + self.assertEqual(req.form['vid'], 'sameetypelist') def test_rest_path_by_attr(self): with self.admin_access.web_request() as req: @@ -91,6 +92,7 @@ 'X firstname AA, X login AB, X modification_date AC, ' 'X surname AD, X login "admin"', rset.printable_rql()) + self.assertEqual(req.form['vid'], 'primary') def test_rest_path_eid(self): with self.admin_access.web_request() as req: @@ -125,6 +127,15 @@ 'X title "hell\'o"', rset.printable_rql()) + def test_rest_path_use_vid_from_rset(self): + with self.admin_access.web_request(headers={'Accept': 'application/rdf+xml'}) as req: + views.VID_BY_MIMETYPE['application/rdf+xml'] = 'rdf' + try: + ctrl, rset = self.process(req, 'CWEType') + finally: + views.VID_BY_MIMETYPE.pop('application/rdf+xml') + self.assertEqual(req.form['vid'], 'rdf') + def test_rest_path_errors(self): with self.admin_access.web_request() as req: self.assertRaises(NotFound, self.process, req, 'CWUser/eid/30000') @@ -141,25 +152,24 @@ self.assertRaises(NotFound, self.process, req, '1/non_action') self.assertRaises(NotFound, self.process, req, 'CWUser/login/admin/non_action') - def test_regexp_path(self): """tests the regexp path resolution""" with self.admin_access.web_request() as req: ctrl, rset = self.process(req, 'add/Task') self.assertEqual(ctrl, 'view') self.assertEqual(rset, None) - self.assertEqual(req.form, {'etype' : "Task", 'vid' : "creation"}) + self.assertEqual(req.form, {'etype': "Task", 'vid': "creation"}) self.assertRaises(NotFound, self.process, req, 'add/foo/bar') def test_nonascii_path(self): oldrules = SimpleReqRewriter.rules - SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo')),] + SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo'))] with self.admin_access.web_request() as req: try: path = str(FakeRequest().url_quote(u'été')) ctrl, rset = self.process(req, path) self.assertEqual(rset, None) - self.assertEqual(req.form, {'vid' : "foo"}) + self.assertEqual(req.form, {'vid': "foo"}) finally: SimpleReqRewriter.rules = oldrules diff -r 7846d26ff91d -r bc2f6f0d7433 web/views/__init__.py --- a/web/views/__init__.py Fri Jul 24 16:19:39 2015 +0200 +++ b/web/views/__init__.py Mon Jul 20 13:55:54 2015 +0200 @@ -77,7 +77,7 @@ #'text/xml': 'xml', # XXX rss, owl... } -def vid_from_rset(req, rset, schema): +def vid_from_rset(req, rset, schema, check_table=True): """given a result set, return a view id""" if rset is None: return 'index' @@ -90,7 +90,7 @@ return 'noresult' # entity result set if not schema.eschema(rset.description[0][0]).final: - if need_table_view(rset, schema): + if check_table and need_table_view(rset, schema): return 'table' if nb_rows == 1: if req.search_state[0] == 'normal': diff -r 7846d26ff91d -r bc2f6f0d7433 web/views/urlpublishing.py --- a/web/views/urlpublishing.py Fri Jul 24 16:19:39 2015 +0200 +++ b/web/views/urlpublishing.py Mon Jul 20 13:55:54 2015 +0200 @@ -60,7 +60,7 @@ from rql import TypeResolverException from cubicweb import RegistryException -from cubicweb.web import NotFound, Redirect, component +from cubicweb.web import NotFound, Redirect, component, views class PathDontMatch(Exception): @@ -201,18 +201,14 @@ return self.handle_etype_attr(req, cls, attrname, value) return self.handle_etype(req, cls) - def set_vid_for_rset(self, req, cls, rset):# cls is there to ease overriding + def set_vid_for_rset(self, req, cls, rset): # cls is there to ease overriding if rset.rowcount == 0: raise NotFound() - # we've to set a default vid here, since vid_from_rset may try to use a - # table view if fetch_rql include some non final relation - if rset.rowcount == 1: - req.form.setdefault('vid', 'primary') - else: # rset.rowcount >= 1 - if len(rset.column_types(0)) > 1: - req.form.setdefault('vid', 'list') - else: - req.form.setdefault('vid', 'sameetypelist') + if 'vid' not in req.form: + # check_table=False tells vid_from_rset not to try to use a table view if fetch_rql + # include some non final relation + req.form['vid'] = views.vid_from_rset(req, rset, req.vreg.schema, + check_table=False) def handle_etype(self, req, cls): rset = req.execute(cls.fetch_rql(req.user))