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, |