entity.py
changeset 3293 69c0ba095536
parent 3230 1d25e928c299
parent 3245 7ef021ac8dec
child 3300 c7c4775a5619
equal deleted inserted replaced
3230:1d25e928c299 3293:69c0ba095536
    12 from logilab.common import interface
    12 from logilab.common import interface
    13 from logilab.common.compat import all
    13 from logilab.common.compat import all
    14 from logilab.common.decorators import cached
    14 from logilab.common.decorators import cached
    15 from logilab.mtconverter import TransformData, TransformError, xml_escape
    15 from logilab.mtconverter import TransformData, TransformError, xml_escape
    16 
    16 
       
    17 from rql import parse
    17 from rql.utils import rqlvar_maker
    18 from rql.utils import rqlvar_maker
    18 
    19 
    19 from cubicweb import Unauthorized
    20 from cubicweb import Unauthorized
    20 from cubicweb.rset import ResultSet
    21 from cubicweb.rset import ResultSet
    21 from cubicweb.selectors import yes
    22 from cubicweb.selectors import yes
    22 from cubicweb.appobject import AppObject
    23 from cubicweb.appobject import AppObject
    23 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
    24 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
       
    25 from cubicweb.rqlrewrite import RQLRewriter
    24 
    26 
    25 from cubicweb.common.uilib import printable_value, soup2xhtml
    27 from cubicweb.common.uilib import printable_value, soup2xhtml
    26 from cubicweb.common.mixins import MI_REL_TRIGGERS
    28 from cubicweb.common.mixins import MI_REL_TRIGGERS
    27 from cubicweb.common.mttransforms import ENGINE
    29 from cubicweb.common.mttransforms import ENGINE
    28 
    30 
   614     # generic vocabulary methods ##############################################
   616     # generic vocabulary methods ##############################################
   615 
   617 
   616     def unrelated_rql(self, rtype, targettype, role, ordermethod=None,
   618     def unrelated_rql(self, rtype, targettype, role, ordermethod=None,
   617                       vocabconstraints=True):
   619                       vocabconstraints=True):
   618         """build a rql to fetch `targettype` entities unrelated to this entity
   620         """build a rql to fetch `targettype` entities unrelated to this entity
   619         using (rtype, role) relation
   621         using (rtype, role) relation.
       
   622 
       
   623         Consider relation permissions so that returned entities may be actually
       
   624         linked by `rtype`.
   620         """
   625         """
   621         ordermethod = ordermethod or 'fetch_unrelated_order'
   626         ordermethod = ordermethod or 'fetch_unrelated_order'
   622         if isinstance(rtype, basestring):
   627         if isinstance(rtype, basestring):
   623             rtype = self.req.vreg.schema.rschema(rtype)
   628             rtype = self.req.vreg.schema.rschema(rtype)
   624         if role == 'subject':
   629         if role == 'subject':
   627         else:
   632         else:
   628             searchedvar, evar = 'S', 'O'
   633             searchedvar, evar = 'S', 'O'
   629             objtype, subjtype = self.e_schema, targettype
   634             objtype, subjtype = self.e_schema, targettype
   630         if self.has_eid():
   635         if self.has_eid():
   631             restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
   636             restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
       
   637             args = {'x': self.eid}
       
   638             if role == 'subject':
       
   639                 securitycheck_args = {'fromeid': self.eid}
       
   640             else:
       
   641                 securitycheck_args = {'toeid': self.eid}
   632         else:
   642         else:
   633             restriction = []
   643             restriction = []
       
   644             args = {}
       
   645             securitycheck_args = {}
       
   646         insertsecurity = (rtype.has_local_role('add') and not
       
   647                           rtype.has_perm(self.req, 'add', **securitycheck_args))
   634         constraints = rtype.rproperty(subjtype, objtype, 'constraints')
   648         constraints = rtype.rproperty(subjtype, objtype, 'constraints')
   635         if vocabconstraints:
   649         if vocabconstraints:
   636             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
   650             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
   637             # will be included as well
   651             # will be included as well
   638             restriction += [cstr.restriction for cstr in constraints
   652             restriction += [cstr.restriction for cstr in constraints
   645                                  mainvar=searchedvar, ordermethod=ordermethod)
   659                                  mainvar=searchedvar, ordermethod=ordermethod)
   646         # ensure we have an order defined
   660         # ensure we have an order defined
   647         if not ' ORDERBY ' in rql:
   661         if not ' ORDERBY ' in rql:
   648             before, after = rql.split(' WHERE ', 1)
   662             before, after = rql.split(' WHERE ', 1)
   649             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
   663             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
   650         return rql
   664         if insertsecurity:
       
   665             rqlexprs = rtype.get_rqlexprs('add')
       
   666             rewriter = RQLRewriter(self.req)
       
   667             rqlst = self.req.vreg.parse(self.req, rql, args)
       
   668             for select in rqlst.children:
       
   669                 rewriter.rewrite(select, [((searchedvar, searchedvar), rqlexprs)],
       
   670                                  select.solutions, args)
       
   671             rql = rqlst.as_string()
       
   672         return rql, args
   651 
   673 
   652     def unrelated(self, rtype, targettype, role='subject', limit=None,
   674     def unrelated(self, rtype, targettype, role='subject', limit=None,
   653                   ordermethod=None):
   675                   ordermethod=None):
   654         """return a result set of target type objects that may be related
   676         """return a result set of target type objects that may be related
   655         by a given relation, with self as subject or object
   677         by a given relation, with self as subject or object
   656         """
   678         """
   657         rql = self.unrelated_rql(rtype, targettype, role, ordermethod)
   679         try:
       
   680             rql, args = self.unrelated_rql(rtype, targettype, role, ordermethod)
       
   681         except Unauthorized:
       
   682             return self.req.empty_rset()
   658         if limit is not None:
   683         if limit is not None:
   659             before, after = rql.split(' WHERE ', 1)
   684             before, after = rql.split(' WHERE ', 1)
   660             rql = '%s LIMIT %s WHERE %s' % (before, limit, after)
   685             rql = '%s LIMIT %s WHERE %s' % (before, limit, after)
   661         if self.has_eid():
   686         return self.req.execute(rql, args, tuple(args))
   662             return self.req.execute(rql, {'x': self.eid})
       
   663         return self.req.execute(rql)
       
   664 
   687 
   665     # relations cache handling ################################################
   688     # relations cache handling ################################################
   666 
   689 
   667     def relation_cached(self, rtype, role):
   690     def relation_cached(self, rtype, role):
   668         """return true if the given relation is already cached on the instance
   691         """return true if the given relation is already cached on the instance
   814             else: # if role == 'object':
   837             else: # if role == 'object':
   815                 for entity in getattr(self, 'reverse_%s' % rschema.type):
   838                 for entity in getattr(self, 'reverse_%s' % rschema.type):
   816                     words += entity.get_words()
   839                     words += entity.get_words()
   817         return words
   840         return words
   818 
   841 
       
   842     @deprecated('[3.2] see new form api')
       
   843     def vocabulary(self, rtype, role='subject', limit=None):
       
   844         """vocabulary functions must return a list of couples
       
   845         (label, eid) that will typically be used to fill the
       
   846         edition view's combobox.
       
   847 
       
   848         If `eid` is None in one of these couples, it should be
       
   849         interpreted as a separator in case vocabulary results are grouped
       
   850         """
       
   851         from logilab.common.testlib import mock_object
       
   852         form = self.vreg.select('forms', 'edition', self.req, entity=self)
       
   853         field = mock_object(name=rtype, role=role)
       
   854         return form.form_field_vocabulary(field, limit)
       
   855 
   819 
   856 
   820 # attribute and relation descriptors ##########################################
   857 # attribute and relation descriptors ##########################################
   821 
   858 
   822 class Attribute(object):
   859 class Attribute(object):
   823     """descriptor that controls schema attribute access"""
   860     """descriptor that controls schema attribute access"""