entity.py
changeset 3293 69c0ba095536
parent 3230 1d25e928c299
parent 3245 7ef021ac8dec
child 3300 c7c4775a5619
--- a/entity.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/entity.py	Thu Sep 17 15:16:53 2009 +0200
@@ -14,6 +14,7 @@
 from logilab.common.decorators import cached
 from logilab.mtconverter import TransformData, TransformError, xml_escape
 
+from rql import parse
 from rql.utils import rqlvar_maker
 
 from cubicweb import Unauthorized
@@ -21,6 +22,7 @@
 from cubicweb.selectors import yes
 from cubicweb.appobject import AppObject
 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
+from cubicweb.rqlrewrite import RQLRewriter
 
 from cubicweb.common.uilib import printable_value, soup2xhtml
 from cubicweb.common.mixins import MI_REL_TRIGGERS
@@ -616,7 +618,10 @@
     def unrelated_rql(self, rtype, targettype, role, ordermethod=None,
                       vocabconstraints=True):
         """build a rql to fetch `targettype` entities unrelated to this entity
-        using (rtype, role) relation
+        using (rtype, role) relation.
+
+        Consider relation permissions so that returned entities may be actually
+        linked by `rtype`.
         """
         ordermethod = ordermethod or 'fetch_unrelated_order'
         if isinstance(rtype, basestring):
@@ -629,8 +634,17 @@
             objtype, subjtype = self.e_schema, targettype
         if self.has_eid():
             restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
+            args = {'x': self.eid}
+            if role == 'subject':
+                securitycheck_args = {'fromeid': self.eid}
+            else:
+                securitycheck_args = {'toeid': self.eid}
         else:
             restriction = []
+            args = {}
+            securitycheck_args = {}
+        insertsecurity = (rtype.has_local_role('add') and not
+                          rtype.has_perm(self.req, 'add', **securitycheck_args))
         constraints = rtype.rproperty(subjtype, objtype, 'constraints')
         if vocabconstraints:
             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
@@ -647,20 +661,29 @@
         if not ' ORDERBY ' in rql:
             before, after = rql.split(' WHERE ', 1)
             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
-        return rql
+        if insertsecurity:
+            rqlexprs = rtype.get_rqlexprs('add')
+            rewriter = RQLRewriter(self.req)
+            rqlst = self.req.vreg.parse(self.req, rql, args)
+            for select in rqlst.children:
+                rewriter.rewrite(select, [((searchedvar, searchedvar), rqlexprs)],
+                                 select.solutions, args)
+            rql = rqlst.as_string()
+        return rql, args
 
     def unrelated(self, rtype, targettype, role='subject', limit=None,
                   ordermethod=None):
         """return a result set of target type objects that may be related
         by a given relation, with self as subject or object
         """
-        rql = self.unrelated_rql(rtype, targettype, role, ordermethod)
+        try:
+            rql, args = self.unrelated_rql(rtype, targettype, role, ordermethod)
+        except Unauthorized:
+            return self.req.empty_rset()
         if limit is not None:
             before, after = rql.split(' WHERE ', 1)
             rql = '%s LIMIT %s WHERE %s' % (before, limit, after)
-        if self.has_eid():
-            return self.req.execute(rql, {'x': self.eid})
-        return self.req.execute(rql)
+        return self.req.execute(rql, args, tuple(args))
 
     # relations cache handling ################################################
 
@@ -816,6 +839,20 @@
                     words += entity.get_words()
         return words
 
+    @deprecated('[3.2] see new form api')
+    def vocabulary(self, rtype, role='subject', limit=None):
+        """vocabulary functions must return a list of couples
+        (label, eid) that will typically be used to fill the
+        edition view's combobox.
+
+        If `eid` is None in one of these couples, it should be
+        interpreted as a separator in case vocabulary results are grouped
+        """
+        from logilab.common.testlib import mock_object
+        form = self.vreg.select('forms', 'edition', self.req, entity=self)
+        field = mock_object(name=rtype, role=role)
+        return form.form_field_vocabulary(field, limit)
+
 
 # attribute and relation descriptors ##########################################