Provide sufficient context to check 'delete' permission in AjaxEditRelationCtxComponent
authorDenis Laxalde <denis.laxalde@logilab.fr>
Thu, 20 Mar 2014 10:41:22 +0100
changeset 10075 136b5f995f8e
parent 10074 ab956b780d4e
child 10077 1a28c0b0a0b4
Provide sufficient context to check 'delete' permission in AjaxEditRelationCtxComponent Call rdef.check only when both fromeid and toeid are available. Though only call it once (for the first encountered related entity). Factorize a bit to keep handling of CSS/JS addition the same. Closes #3670209.
web/component.py
web/test/unittest_views_basecontrollers.py
--- a/web/component.py	Mon Dec 01 11:13:10 2014 +0100
+++ b/web/component.py	Thu Mar 20 10:41:22 2014 +0100
@@ -598,27 +598,41 @@
         w(self.rdef.rtype.display_name(self._cw, self.role,
                                        context=self.entity.cw_etype))
 
+    def add_js_css(self):
+        self._cw.add_js(('jquery.ui.js', 'cubicweb.widgets.js'))
+        self._cw.add_js(('cubicweb.ajax.js', 'cubicweb.ajax.box.js'))
+        self._cw.add_css('jquery.ui.css')
+        return True
+
     def render_body(self, w):
         req = self._cw
         entity = self.entity
         related = entity.related(self.rtype, self.role)
         if self.role == 'subject':
             mayadd = self.rdef.has_perm(req, 'add', fromeid=entity.eid)
-            maydel = self.rdef.has_perm(req, 'delete', fromeid=entity.eid)
         else:
             mayadd = self.rdef.has_perm(req, 'add', toeid=entity.eid)
-            maydel = self.rdef.has_perm(req, 'delete', toeid=entity.eid)
-        if mayadd or maydel:
-            req.add_js(('jquery.ui.js', 'cubicweb.widgets.js'))
-            req.add_js(('cubicweb.ajax.js', 'cubicweb.ajax.box.js'))
-            req.add_css('jquery.ui.css')
+        js_css_added = False
+        if mayadd:
+            js_css_added = self.add_js_css()
         _ = req._
         if related:
+            maydel = None
             w(u'<table class="ajaxEditRelationTable">')
             for rentity in related.entities():
+                if maydel is None:
+                    # Only check permission for the first related.
+                    if self.role == 'subject':
+                        fromeid, toeid = entity.eid, rentity.eid
+                    else:
+                        fromeid, toeid = rentity.eid, entity.eid
+                    maydel = self.rdef.has_perm(
+                            req, 'delete', fromeid=fromeid, toeid=toeid)
                 # for each related entity, provide a link to remove the relation
                 subview = rentity.view(self.item_vid)
                 if maydel:
+                    if not js_css_added:
+                        js_css_added = self.add_js_css()
                     jscall = unicode(js.ajaxBoxRemoveLinkedEntity(
                         self.__regid__, entity.eid, rentity.eid,
                         self.fname_remove,
--- a/web/test/unittest_views_basecontrollers.py	Mon Dec 01 11:13:10 2014 +0100
+++ b/web/test/unittest_views_basecontrollers.py	Thu Mar 20 10:41:22 2014 +0100
@@ -31,6 +31,7 @@
 from logilab.common.decorators import monkeypatch
 
 from cubicweb import Binary, NoSelectableObject, ValidationError
+from cubicweb.schema import RRQLExpression
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.utils import json_dumps
 from cubicweb.uilib import rql_for_eid
@@ -808,6 +809,22 @@
                 req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
                 [['javascript']])
 
+    def test_maydel_perms(self):
+        """Check that AjaxEditRelationCtxComponent calls rdef.check with a
+        sufficient context"""
+        self.remote_call('tag_entity', self.john.eid, ['python'])
+        with self.temporary_permissions(
+                (self.schema['tags'].rdefs['Tag', 'CWUser'],
+                 {'delete': (RRQLExpression('S owned_by U'), )}, )):
+            req = self.request(rql='CWUser P WHERE P login "John"',
+                               pageid='123', fname='view')
+            ctrl = self.ctrl(req)
+            rset = self.john.as_rset()
+            rset.req = req
+            source = ctrl.publish()
+            # maydel jscall
+            self.assertIn('ajaxBoxRemoveLinkedEntity', source)
+
     def test_pending_insertion(self):
         with self.remote_calling('add_pending_inserts', [['12', 'tags', '13']]) as (_, req):
             deletes = get_pending_deletes(req)