selectors.py
branchtls-sprint
changeset 835 7dcb11dd443e
parent 833 8c6bfd9158fb
child 837 931e0dac47f0
child 838 f2c56312b03a
equal deleted inserted replaced
834:50d5ca1180b1 835:7dcb11dd443e
   111         TRACED_OIDS = ()
   111         TRACED_OIDS = ()
   112         return traceback is None
   112         return traceback is None
   113 
   113 
   114 
   114 
   115 # abstract selectors ##########################################################
   115 # abstract selectors ##########################################################
       
   116 
   116 class AbstractSelectorMixIn(object):
   117 class AbstractSelectorMixIn(object):
   117     """convenience mix-in for selectors that depends on class attributes
   118     """convenience mix-in for selectors that depends on class attributes
   118     cf. `cubicweb.web.action.LinkToEntityAction` for instance
   119     cf. `cubicweb.web.action.LinkToEntityAction` for instance
   119     """
   120     """
   120     def __call__(self, cls, *args, **kwargs):
   121     def __call__(self, cls, *args, **kwargs):
   121         self.concretize(cls)
   122         self.concretize(cls)
   122         super(AbstractSelectorMixIn, self).__call__(cls, *args, **kwargs)
   123         return super(AbstractSelectorMixIn, self).__call__(cls, *args, **kwargs)
       
   124 
   123 
   125 
   124 class EClassSelector(Selector):
   126 class EClassSelector(Selector):
   125     """abstract class for selectors working on the entity classes of the result
   127     """abstract class for selectors working on the entity classes of the result
   126     set. Its __call__ method has the following behaviour:
   128     set. Its __call__ method has the following behaviour:
   127 
   129 
   132       - `once_is_enough` is True, in which case the first non-zero score is
   134       - `once_is_enough` is True, in which case the first non-zero score is
   133         returned
   135         returned
   134       - `once_is_enough` is False, in which case if score_class return 0, 0 is
   136       - `once_is_enough` is False, in which case if score_class return 0, 0 is
   135         returned
   137         returned
   136     """
   138     """
   137     def __init__(self, once_is_enough=False, sumscores=True):
   139     def __init__(self, once_is_enough=False):
   138         self.once_is_enough = once_is_enough
   140         self.once_is_enough = once_is_enough
   139         self.sumscores = sumscores
       
   140     
   141     
   141     @lltrace
   142     @lltrace
   142     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   143     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   143         if not rset:
   144         if not rset:
   144             return 0
   145             return 0
   595     def __call__(self, cls, req, *args, **kwargs):
   596     def __call__(self, cls, req, *args, **kwargs):
   596         rschema = cls.schema.rschema(self.rtype)
   597         rschema = cls.schema.rschema(self.rtype)
   597         if not (rschema.has_perm(req, self.action)
   598         if not (rschema.has_perm(req, self.action)
   598                 or rschema.has_local_role(self.action)):
   599                 or rschema.has_local_role(self.action)):
   599             return 0
   600             return 0
   600         return super(relation_possible, self).__call__(cls, req, *args, **kwargs)
   601         score = super(relation_possible, self).__call__(cls, req, *args, **kwargs)
       
   602         return score
   601         
   603         
   602     def score_class(self, eclass, req):
   604     def score_class(self, eclass, req):
   603         eschema = eclass.e_schema
   605         eschema = eclass.e_schema
   604         try:
   606         try:
   605             if self.role == 'object':
   607             if self.role == 'object':
   608                 rschema = eschema.subject_relation(self.rtype)
   610                 rschema = eschema.subject_relation(self.rtype)
   609         except KeyError:
   611         except KeyError:
   610             return 0
   612             return 0
   611         if self.target_etype is not None:
   613         if self.target_etype is not None:
   612             try:
   614             try:
   613                 if self.role == 'object':
   615                 if self.role == 'subject':
   614                     return self.target_etype in rschema.objects(eschema)
   616                     return int(self.target_etype in rschema.objects(eschema))
   615                 else:
   617                 else:
   616                     return self.target_etype in rschema.subjects(eschema)
   618                     return int(self.target_etype in rschema.subjects(eschema))
   617             except KeyError, ex:
   619             except KeyError, ex:
   618                 return 0
   620                 return 0
   619         return 1
   621         return 1
       
   622 
   620 
   623 
   621 class abstract_relation_possible(AbstractSelectorMixIn, relation_possible):
   624 class abstract_relation_possible(AbstractSelectorMixIn, relation_possible):
   622     def __init__(self, action='read', once_is_enough=False):
   625     def __init__(self, action='read', once_is_enough=False):
   623         super(abstract_relation_possible, self).__init__(None, None, None,
   626         super(abstract_relation_possible, self).__init__(None, None, None,
   624                                                          action, once_is_enough)
   627                                                          action, once_is_enough)
   625 
   628 
   626     def concretize(self, cls):
   629     def concretize(self, cls):
   627         self.rtype = cls.rtype
   630         self.rtype = cls.rtype
   628         self.role = role(cls)
   631         self.role = role(cls)
   629         self.target_etype = getattr(cls, 'etype', None)
   632         self.target_etype = getattr(cls, 'etype', None)
       
   633 
   630 
   634 
   631 class has_editable_relation(EntitySelector):
   635 class has_editable_relation(EntitySelector):
   632     """accept if some relations for an entity found in the result set is
   636     """accept if some relations for an entity found in the result set is
   633     editable by the logged user.
   637     editable by the logged user.
   634 
   638 
   665         self.role = role
   669         self.role = role
   666         
   670         
   667     def score_entity(self, entity):
   671     def score_entity(self, entity):
   668         rschema = entity.schema.rschema(self.rtype)
   672         rschema = entity.schema.rschema(self.rtype)
   669         if self.role == 'subject':
   673         if self.role == 'subject':
   670             if not rschema.has_perm(req, 'add', fromeid=entity.eid):
   674             if not rschema.has_perm(entity.req, 'add', fromeid=entity.eid):
   671                 return 0
   675                 return 0
   672         elif not rschema.has_perm(req, 'add', toeid=entity.eid):
   676         elif not rschema.has_perm(entity.req, 'add', toeid=entity.eid):
   673             return 0
   677             return 0
   674         return 1
   678         return 1
   675 
   679 
   676 class abstract_may_add_relation(AbstractSelectorMixIn, may_add_relation):
   680 class abstract_may_add_relation(AbstractSelectorMixIn, may_add_relation):
   677     def __init__(self, once_is_enough=False):
   681     def __init__(self, once_is_enough=False):
   704     
   708     
   705     def score_entity(self, entity):
   709     def score_entity(self, entity):
   706         rset = entity.related(self.rtype, self.role)
   710         rset = entity.related(self.rtype, self.role)
   707         if self.target_etype:
   711         if self.target_etype:
   708             return any(x for x, in rset.description if x == self.target_etype)
   712             return any(x for x, in rset.description if x == self.target_etype)
   709         return bool(rset)
   713         return rset and 1 or 0
   710 
   714 
   711 
   715 
   712 class abstract_has_related_entities(AbstractSelectorMixIn, has_related_entities):
   716 class abstract_has_related_entities(AbstractSelectorMixIn, has_related_entities):
   713     def __init__(self, once_is_enough=False):
   717     def __init__(self, once_is_enough=False):
   714         super(abstract_has_related_entities, self).__init__(None, None,
   718         super(abstract_has_related_entities, self).__init__(None, None,