--- a/selectors.py Tue Feb 17 09:59:15 2009 +0100
+++ b/selectors.py Tue Feb 17 12:33:57 2009 +0100
@@ -105,183 +105,24 @@
TRACED_OIDS = ()
return traceback is None
-# very basic selectors ########################################################
-
-def yes(cls, *args, **kwargs):
- """accept everything"""
- return 1
-yes_selector = deprecated_function(yes)
-
-@lltrace
-def none_rset(cls, req, rset, *args, **kwargs):
- """accept no result set"""
- if rset is None:
- return 1
- return 0
-norset_selector = deprecated_function(none_rset)
-
-@lltrace
-def any_rset(cls, req, rset, *args, **kwargs):
- """accept result set, whatever the number of result"""
- if rset is not None:
- return 1
- return 0
-rset_selector = deprecated_function(any_rset)
-
-@lltrace
-def nonempty_rset(cls, req, rset, *args, **kwargs):
- """accept any non empty result set"""
- if rset is not None and rset.rowcount:
- return 1
- return 0
-anyrset_selector = deprecated_function(nonempty_rset)
-
-@lltrace
-def empty_rset(cls, req, rset, *args, **kwargs):
- """accept empty result set"""
- if rset is not None and rset.rowcount == 0:
- return 1
- return 0
-emptyrset_selector = deprecated_function(empty_rset)
-
-@lltrace
-def one_line_rset(cls, req, rset, row=None, *args, **kwargs):
- """accept result set with a single line of result"""
- if rset is not None and (row is not None or rset.rowcount == 1):
- return 1
- return 0
-onelinerset_selector = deprecated_function(one_line_rset)
-
-@lltrace
-def two_lines_rset(cls, req, rset, *args, **kwargs):
- """accept result set with *at least* two lines of result"""
- if rset is not None and rset.rowcount > 1:
- return 1
- return 0
-twolinerset_selector = deprecated_function(two_lines_rset)
-
-@lltrace
-def two_cols_rset(cls, req, rset, *args, **kwargs):
- """accept result set with at least one line and two columns of result"""
- if rset is not None and rset.rowcount > 0 and len(rset.rows[0]) > 1:
- return 1
- return 0
-twocolrset_selector = deprecated_function(two_cols_rset)
-
-@lltrace
-def paginated_rset(cls, req, rset, *args, **kwargs):
- """accept result sets with more rows than the page size
- """
- page_size = kwargs.get('page_size')
- if page_size is None:
- page_size = req.form.get('page_size')
- if page_size is None:
- page_size = req.property_value('navigation.page-size')
- else:
- page_size = int(page_size)
- if rset is None or len(rset) <= page_size:
- return 0
- return 1
-largerset_selector = deprecated_function(paginated_rset)
-
-@lltrace
-def sorted_rset(cls, req, rset, row=None, col=0, **kwargs):
- """accept sorted result set"""
- rqlst = rset.syntax_tree()
- if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
- return 0
- return 2
-sortedrset_selector = deprecated_function(sorted_rset)
-
-@lltrace
-def one_etype_rset(cls, req, rset, *args, **kwargs):
- """accept result set where entities in the first columns are all of the
- same type
- """
- if len(rset.column_types(0)) != 1:
- return 0
- return 1
-oneetyperset_selector = deprecated_function(one_etype_rset)
-
-@lltrace
-def two_etypes_rset(cls, req, rset, **kwargs):
- """accepts resultsets containing several entity types"""
- if rset:
- etypes = rset.column_types(0)
- if len(etypes) > 1:
- return 1
- return 0
-multitype_selector = deprecated_function(two_etypes_rset)
-
-
-class match_search_state(Selector):
- def __init__(self, *expected):
- self.expected = expected
-
- @lltrace
- def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
- """checks if the current request search state is in one of the expected states
- the wrapped class
-
- search state should be either 'normal' or 'linksearch' (eg searching for an
- object to create a relation with another)
- """
- try:
- if not req.search_state[0] in self.expected:
- return 0
- except AttributeError:
- return 1 # class doesn't care about search state, accept it
- return 1
-
-
-class match_form_params(match_search_state):
- """check if parameters specified as initializer arguments are specified
- in request form parameters
- """
- @lltrace
- def __call__(self, cls, req, *args, **kwargs):
- score = 0
- for param in self.expected:
- val = req.form.get(param)
- if not val:
- return 0
- score += 1
- return len(self.expected)
-
-
-class match_kwargs(match_search_state):
- """check if parameters specified as initializer arguments are specified
- in named parameters
- """
- @lltrace
- def __call__(self, cls, req, *args, **kwargs):
- for arg in self.expected:
- if not arg in kwargs:
- return 0
- return len(self.expected)
-
-
-@lltrace
-def anonymous_user(cls, req, *args, **kwargs):
- """accept if user is anonymous"""
- if req.cnx.anonymous_connection:
- return 1
- return 0
-anonymous_selector = deprecated_function(anonymous_user)
-
-@lltrace
-def authenticated_user(cls, req, *args, **kwargs):
- """accept if user is authenticated"""
- return not anonymous_user(cls, req, *args, **kwargs)
-not_anonymous_selector = deprecated_function(authenticated_user)
# abstract selectors ##########################################################
class EClassSelector(Selector):
"""abstract class for selectors working on the entity classes of the result
- set
+ set. Its __call__ method has the following behaviour:
+
+ * if row is specified, return the score returned by the score_class method
+ called with the entity class found in the specified cell
+ * else return the sum of score returned by the score_class method for each
+ entity type found in the specified column, unless:
+ - `once_is_enough` is True, in which case the first non-zero score is
+ returned
+ - `once_is_enough` is False, in which case if score_class return 0, 0 is
+ returned
"""
- once_is_enough = False
+ def __init__(self, once_is_enough=False):
+ self.once_is_enough = once_is_enough
@lltrace
def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
@@ -292,28 +133,44 @@
for etype in rset.column_types(col):
if etype is None: # outer join
continue
- if etype in BASE_TYPES:
- return 0
- escore = self.score_class(cls.vreg.etype_class(etype), req)
- if not escore:
+ escore = self.score(cls, req, etype)
+ if not escore and not self.once_is_enough:
return 0
elif self.once_is_enough:
return escore
score += escore
else:
etype = rset.description[row][col]
- if etype is not None and not etype in BASE_TYPES:
- score = self.score_class(cls.vreg.etype_class(etype), req)
+ if etype is not None:
+ score = self.score(cls, req, etype)
return score and (score + 1)
+ def score(self, cls, req, etype):
+ if etype in BASE_TYPES:
+ return 0
+ return self.score_class(cls.vreg.etype_class(etype), req)
+
def score_class(self, eclass, req):
raise NotImplementedError()
-class EntitySelector(Selector):
+class EntitySelector(EClassSelector):
"""abstract class for selectors working on the entity instances of the
- result set
+ result set. Its __call__ method has the following behaviour:
+
+ * if row is specified, return the score returned by the score_entity method
+ called with the entity instance found in the specified cell
+ * else return the sum of score returned by the score_entity method for each
+ entity found in the specified column, unless:
+ - `once_is_enough` is True, in which case the first non-zero score is
+ returned
+ - `once_is_enough` is False, in which case if score_class return 0, 0 is
+ returned
+
+ note: None values (resulting from some outer join in the query) are not
+ considered.
"""
+
@lltrace
def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
if not rset:
@@ -323,12 +180,11 @@
for row, rowvalue in enumerate(rset.rows):
if rowvalue[col] is None: # outer join
continue
- try:
- escore = self.score(req, rset, row, col))
- except NotAnEntity:
+ escore = self.score(req, rset, row, col))
+ if not escore and not self.once_is_enough:
return 0
- if not escore:
- return 0
+ elif self.once_is_enough:
+ return escore
score += escore
else:
etype = rset.description[row][col]
@@ -345,21 +201,284 @@
def score_entity(self, entity):
raise NotImplementedError()
+
+# very basic selectors ########################################################
+
+def yes(cls, *args, **kwargs):
+ """accept everything"""
+ return 1
+
+@lltrace
+def none_rset(cls, req, rset, *args, **kwargs):
+ """accept no result set (e.g. given rset is None)"""
+ if rset is None:
+ return 1
+ return 0
+
+@lltrace
+def any_rset(cls, req, rset, *args, **kwargs):
+ """accept result set, whatever the number of result it contains"""
+ if rset is not None:
+ return 1
+ return 0
+
+@lltrace
+def nonempty_rset(cls, req, rset, *args, **kwargs):
+ """accept any non empty result set"""
+ if rset is not None and rset.rowcount:
+ return 1
+ return 0
+
+@lltrace
+def empty_rset(cls, req, rset, *args, **kwargs):
+ """accept empty result set"""
+ if rset is not None and rset.rowcount == 0:
+ return 1
+ return 0
+
+@lltrace
+def one_line_rset(cls, req, rset, row=None, *args, **kwargs):
+ """if row is specified, accept result set with a single line of result,
+ else accepts anyway
+ """
+ if rset is not None and (row is not None or rset.rowcount == 1):
+ return 1
+ return 0
+
+@lltrace
+def two_lines_rset(cls, req, rset, *args, **kwargs):
+ """accept result set with *at least* two lines of result"""
+ if rset is not None and rset.rowcount > 1:
+ return 1
+ return 0
+
+@lltrace
+def two_cols_rset(cls, req, rset, *args, **kwargs):
+ """accept result set with at least one line and two columns of result"""
+ if rset is not None and rset.rowcount and len(rset.rows[0]) > 1:
+ return 1
+ return 0
+
+@lltrace
+def paginated_rset(cls, req, rset, *args, **kwargs):
+ """accept result set with more lines than the page size.
+
+ Page size is searched in (respecting order):
+ * a page_size argument
+ * a page_size form parameters
+ * the navigation.page-size property
+ """
+ page_size = kwargs.get('page_size')
+ if page_size is None:
+ page_size = req.form.get('page_size')
+ if page_size is None:
+ page_size = req.property_value('navigation.page-size')
+ else:
+ page_size = int(page_size)
+ if rset is None or rset.rowcount <= page_size:
+ return 0
+ return 1
+
+@lltrace
+def sorted_rset(cls, req, rset, row=None, col=0, **kwargs):
+ """accept sorted result set"""
+ rqlst = rset.syntax_tree()
+ if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
+ return 0
+ return 2
+
+@lltrace
+def one_etype_rset(cls, req, rset, row=None, col=0, *args, **kwargs):
+ """accept result set where entities in the specified column (or 0) are all
+ of the same type
+ """
+ if len(rset.column_types(col)) != 1:
+ return 0
+ return 1
+
+@lltrace
+def two_etypes_rset(cls, req, rset, row=None, col=0, **kwargs):
+ """accept result set where entities in the specified column (or 0) are not
+ of the same type
+ """
+ if rset:
+ etypes = rset.column_types(col)
+ if len(etypes) > 1:
+ return 1
+ return 0
+
+class non_final_entity(EClassSelector):
+ """accept if entity type found in the result set is non final.
+
+ See `EClassSelector` documentation for behaviour when row is not specified.
+ """
+ def score(self, cls, req, etype):
+ if etype in BASE_TYPES:
+ return 0
+ return 1
+
+@lltrace
+def anonymous_user(cls, req, *args, **kwargs):
+ """accept if user is anonymous"""
+ if req.cnx.anonymous_connection:
+ return 1
+ return 0
+
+@lltrace
+def authenticated_user(cls, req, *args, **kwargs):
+ """accept if user is authenticated"""
+ return not anonymous_user(cls, req, *args, **kwargs)
+
+@lltrace
+def primary_view(cls, req, rset, row=None, col=0, view=None, **kwargs):
+ """accept if view given as named argument is a primary view, or if no view
+ is given
+ """
+ if view is not None and not view.is_primary():
+ return 0
+ return 1
+
+@lltrace
+def match_context_prop(cls, req, rset, row=None, col=0, context=None,
+ **kwargs):
+ """accept if:
+ * no context given
+ * context (`basestring`) is matching the context property value for the
+ given cls
+ """
+ propval = req.property_value('%s.%s.context' % (cls.__registry__, cls.id))
+ if not propval:
+ propval = cls.context
+ if context is not None and propval and context != propval:
+ return 0
+ return 1
+
+
+class match_search_state(Selector):
+ """accept if the current request search state is in one of the expected
+ states given to the initializer
+
+ :param expected: either 'normal' or 'linksearch' (eg searching for an
+ object to create a relation with another)
+ """
+ def __init__(self, *expected):
+ self.expected = expected
+
+ @lltrace
+ def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
+ try:
+ if not req.search_state[0] in self.expected:
+ return 0
+ except AttributeError:
+ return 1 # class doesn't care about search state, accept it
+ return 1
+
+
+class match_form_params(match_search_state):
+ """accept if parameters specified as initializer arguments are specified
+ in request's form parameters
+
+ :param *expected: parameters (eg `basestring`) which are expected to be
+ found in request's form parameters
+ """
+
+ @lltrace
+ def __call__(self, cls, req, *args, **kwargs):
+ score = 0
+ for param in self.expected:
+ val = req.form.get(param)
+ if not val:
+ return 0
+ score += 1
+ return len(self.expected)
+
+
+class match_kwargs(match_search_state):
+ """accept if parameters specified as initializer arguments are specified
+ in named arguments given to the selector
+
+ :param *expected: parameters (eg `basestring`) which are expected to be
+ found in named arguments (kwargs)
+ """
+
+ @lltrace
+ def __call__(self, cls, req, *args, **kwargs):
+ for arg in self.expected:
+ if not arg in kwargs:
+ return 0
+ return len(self.expected)
+
+
+class match_user_groups(Selector):
+ """accept if logged users is in at least one of the given groups. Returned
+ score is the number of groups in which the user is.
+
+ If the special 'owners' group is given:
+ * if row is specified check the entity at the given row/col is owned by the
+ logged user
+ * if row is not specified check all entities in col are owned by the logged
+ user
+
+ :param *required_groups: name of groups (`basestring`) in which the logged
+ user should be
+ """
+
+ def __init__(self, *required_groups):
+ self.required_groups = required_groups
+
+ @lltrace
+ def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
+ user = req.user
+ if user is None:
+ return int('guests' in self.required_groups)
+ score = user.matching_groups(self.required_groups)
+ if not score and 'owners' in self.required_groups and rset:
+ nbowned = 0
+ if row is not None:
+ if not user.owns(rset[row][col]):
+ return 0
+ score = 1
+ else:
+ score = all(user.owns(r[col or 0]) for r in rset)
+ return 0
+
+
+class appobject_selectable(Selector):
+ """accept with another appobject is selectable using selector's input
+ context.
+
+ :param registry: a registry name (`basestring`)
+ :param oid: an object identifier (`basestring`)
+ """
+ def __init__(self, registry, oid):
+ self.registry = registry
+ self.oid = oid
+
+ def __call__(self, cls, req, rset, *args, **kwargs):
+ try:
+ cls.vreg.select_object(self.registry, self.oid, req, rset, *args, **kwargs)
+ return 1
+ except NoSelectableObject:
+ return 0
+
+
# not so basic selectors ######################################################
class implements(EClassSelector):
- """initializer takes a list of interfaces or entity types as argument
-
- * if row is None, return the number of implemented interfaces for each
- entity's class in the result set at the specified column (or column 0).
- If any class has no matching interface, return 0.
- * if row is specified, return number of implemented interfaces by the
- entity's class at this row (and column)
+ """accept if entity class found in the result set implements at least one
+ of the interfaces given as argument. Returned score is the number of
+ implemented interfaces.
+
+ See `EClassSelector` documentation for behaviour when row is not specified.
- if some interface is an entity class, the score will reflect class
- proximity so the most specific object'll be selected
+ :param *expected_ifaces: expected interfaces. An interface may be a class
+ or an entity type (e.g. `basestring`) in which case
+ the associated class will be searched in the
+ registry (at selection time)
+
+ note: when interface is an entity class, the score will reflect class
+ proximity so the most specific object'll be selected
"""
-
def __init__(self, *expected_ifaces):
self.expected_ifaces = expected_ifaces
@@ -376,21 +495,30 @@
# adjust score if the interface is an entity class
if iface is eclass:
score += len(eclass.e_schema.ancestors())
- print 'is majoration', len(eclass.e_schema.ancestors())
+# print 'is majoration', len(eclass.e_schema.ancestors())
else:
parents = [e.type for e in eclass.e_schema.ancestors()]
for index, etype in enumerate(reversed(parents)):
basecls = eclass.vreg.etype_class(etype)
if iface is basecls:
score += index
- print 'etype majoration', index
+# print 'etype majoration', index
break
return score
class specified_etype_implements(implements):
- """return the "interface score" for class associated to 'etype' (expected in
- request form or arguments)
+ """accept if entity class specified using an 'etype' parameters in name
+ argument or request form implements at least one of the interfaces given as
+ argument. Returned score is the number of implemented interfaces.
+
+ :param *expected_ifaces: expected interfaces. An interface may be a class
+ or an entity type (e.g. `basestring`) in which case
+ the associated class will be searched in the
+ registry (at selection time)
+
+ note: when interface is an entity class, the score will reflect class
+ proximity so the most specific object'll be selected
"""
@lltrace
@@ -406,29 +534,32 @@
class relation_possible(EClassSelector):
- """initializer takes relation name as argument and an optional role (default
- as subject) and target type (default to unspecified)
-
- * if row is None, return 1 if every entity's class in the result set at the
- specified column (or column 0) may have this relation (as role). If target
- type is specified, check the relation's end may be of this target type.
-
- * if row is specified, check relation is supported by the entity's class at
- this row (and column)
+ """accept if entity class found in the result set support the relation.
+
+ See `EClassSelector` documentation for behaviour when row is not specified.
+
+ :param rtype: a relation type (`basestring`)
+ :param role: the role of the result set entity in the relation. 'subject' or
+ 'object', default to 'subject'.
+ :param target_type: if specified, check the relation's end may be of this
+ target type (`basestring`)
+ :param action: a relation schema action (one of 'read', 'add', 'delete')
+ which must be granted to the logged user, else a 0 score will
+ be returned
"""
def __init__(self, rtype, role='subject', target_etype=None,
- permission='read', once_is_enough=False):
+ action='read', once_is_enough=False):
+ super(relation_possible, self).__init__(once_is_enough)
self.rtype = rtype
self.role = role
self.target_etype = target_etype
- self.permission = permission
- self.once_is_enough = once_is_enough
+ self.action = action
@lltrace
def __call__(self, cls, *args, **kwargs):
rschema = cls.schema.rschema(self.rtype)
- if not (rschema.has_perm(req, self.permission)
- or rschema.has_local_role(self.permission)):
+ if not (rschema.has_perm(req, self.action)
+ or rschema.has_local_role(self.action)):
return 0
return super(relation_possible, self)(cls, *args, **kwargs)
@@ -452,56 +583,11 @@
return 1
-class non_final_entity(EClassSelector):
- """initializer takes no argument
-
- * if row is None, return 1 if there are only non final entity's class in the
- result set at the specified column (or column 0)
- * if row is specified, return 1 if entity's class at this row (and column)
- isn't final
- """
- def score_class(self, eclass, req):
- return int(not eclass.e_schema.is_final())
-
-
-class match_user_groups(Selector):
- """initializer takes users group as argument
+class has_editable_relation(EntitySelector):
+ """accept if some relations for an entity found in the result set is
+ editable by the logged user.
- * check logged user is in one of the given groups. If special 'owners' group
- given:
- - if row is specified check the entity at the given row/col is owned by
- the logged user
- - if row is not specified check all entities in col are owned by the
- logged user
- """
-
- def __init__(self, *required_groups):
- self.required_groups = required_groups
-
- @lltrace
- def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
- user = req.user
- if user is None:
- return int('guests' in self.require_groups)
- score = user.matching_groups(self.require_groups)
- if not score and 'owners' in self.require_groups and rset:
- nbowned = 0
- if row is not None:
- if not user.owns(rset[row][col]):
- return 0
- score = 1
- else:
- score = all(user.owns(r[col or 0]) for r in rset)
- return 0
-
-
-class has_editable_relation(EntitySelector):
- """initializer takes no argument
-
- * if row is specified check the entity at the given row/col has some
- relation editable by the logged user
- * if row is not specified check all entities in col are owned have some
- relation editable by the logged userlogged user
+ See `EntitySelector` documentation for behaviour when row is not specified.
"""
def score_entity(self, entity):
@@ -518,12 +604,14 @@
class may_add_relation(EntitySelector):
- """initializer takes a relation type and optional role (default to
- 'subject') as argument
+ """accept if the relation can be added to an entity found in the result set
+ by the logged user.
+
+ See `EntitySelector` documentation for behaviour when row is not specified.
- if row is specified check the relation may be added to the entity at the
- given row/col (if row specified) or to every entities in the given col (if
- row is not specified)
+ :param rtype: a relation type (`basestring`)
+ :param role: the role of the result set entity in the relation. 'subject' or
+ 'object', default to 'subject'.
"""
def __init__(self, rtype, role='subject'):
@@ -534,28 +622,60 @@
rschema = entity.schema.rschema(self.rtype)
if self.role == 'subject':
if not rschema.has_perm(req, 'add', fromeid=entity.eid):
- return False
+ return 0
elif not rschema.has_perm(req, 'add', toeid=entity.eid):
- return False
- return True
+ return 0
+ return 1
+
+
+class has_related_entities(EntitySelector):
+ """accept if entity found in the result set has some linked entities using
+ the specified relation (optionaly filtered according to the specified target
+ type).
+
+ See `EntitySelector` documentation for behaviour when row is not specified.
+
+ :param rtype: a relation type (`basestring`)
+ :param role: the role of the result set entity in the relation. 'subject' or
+ 'object', default to 'subject'.
+ :param target_type: if specified, check the relation's end may be of this
+ target type (`basestring`)
+ """
+ def __init__(self, rtype, role='subject', target_etype=None,
+ once_is_enough=False):
+ self.rtype = rtype
+ self.role = role
+ self.target_etype = target_etype
+ self.once_is_enough = once_is_enough
+
+ def score_entity(self, entity):
+ rset = entity.related(self.rtype, self.role)
+ if self.target_etype:
+ return any(x for x, in rset.description if x == self.target_etype)
+ return bool(rset)
class has_permission(EntitySelector):
- """initializer takes a schema action (eg 'read'/'add'/'delete'/'update') as
- argument
+ """accept if user has the permission to do the requested action on a result
+ set entity.
+
+ * if row is specified, return 1 if user has the permission on the entity
+ instance found in the specified cell
+ * else return a positive score if user has the permission for every entity
+ in the found in the specified column
- * if row is specified check user has permission to do the requested action
- on the entity at the given row/col
- * if row is specified check user has permission to do the requested action
- on all entities in the given col
+ note: None values (resulting from some outer join in the query) are not
+ considered.
+
+ :param action: an entity schema action (eg 'read'/'add'/'delete'/'update')
"""
- def __init__(self, schema_action):
- self.schema_action = schema_action
+ def __init__(self, action):
+ self.action = action
@lltrace
def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
user = req.user
- action = self.schema_action
+ action = self.action
if row is None:
score = 0
need_local_check = []
@@ -572,53 +692,48 @@
else:
# even a local role won't be enough
return 0
- score += accepted
+ score += 1
if need_local_check:
# check local role for entities of necessary types
for i, row in enumerate(rset):
if not rset.description[i][0] in need_local_check:
continue
- if not self.score_entity(rset.get_entity(i, col)):
+ if not self.score(req, rset, i, col)):
return 0
- score += 1
+ score += 1
return score
- if rset.description[row][col] in BASE_TYPES:
- return 0
- return self.score_entity(rset.get_entity(row, col))
+ return self.score(req, rset, i, col)
def score_entity(self, entity):
- if entity.has_perm(self.schema_action):
+ if entity.has_perm(self.action):
return 1
return 0
class has_add_permission(EClassSelector):
- """return 1 if the user may add some entity of the types found in the
- result set (0 else)
+ """accept if logged user has the add permission on entity class found in the
+ result set, and class is not a strict subobject.
+
+ See `EClassSelector` documentation for behaviour when row is not specified.
"""
- def score_class(self, eclass, req):
- eschema = eclass.e_schema
+ def score(self, cls, req, etype):
+ eschema = cls.schema.eschema(etype)
if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
and eschema.has_perm(req, 'add'):
return 1
return 0
-
-class score_entity(EntitySelector):
- """initializer takes a function as argument (which is expected to take an
- entity as argument)
-
- return the score returned by the function on the entity at the given row/col
- (if row specified) or the sum of the score for every entities in the given
- col (if row is not specified). Return 0 at the first entity scoring to zero.
- """
- def __init__(self, scorefunc):
- self.score_entity = scorefunc
-
class rql_condition(EntitySelector):
- """initializer takes a rql expression as argument (which should use X
- variable to represent the context entity).
+ """accept if an arbitrary rql return some results for an eid found in the
+ result set. Returned score is the number of items returned by the rql
+ condition.
+
+ See `EntitySelector` documentation for behaviour when row is not specified.
+
+ :param expression: basestring containing an rql expression, which should use
+ X variable to represent the context entity and may use U
+ to represent the logged user
return the sum of the number of items returned by the rql condition as score
or 0 at the first entity scoring to zero.
@@ -638,93 +753,53 @@
class but_etype(EntitySelector):
- """initializer takes an entity type as argument.
+ """accept if the given entity types are not found in the result set.
- return 0 if an entity type is this type, else 1.
+ See `EntitySelector` documentation for behaviour when row is not specified.
+
+ :param *etypes: entity types (`basestring`) which should be refused
"""
- def __init__(self, etype):
- self.etype = etype
+ def __init__(self, *etypes):
+ self.but_etypes = etypes
def score(self, req, rset, row, col):
- if rset.description[row][col] == self.etype:
+ if rset.description[row][col] in self.but_etypes:
return 0
return 1
-
-class appobject_selectable(Selector):
- """initializer takes a registry and oid of another vobject
+
+class score_entity(EntitySelector):
+ """accept if some arbitrary function return a positive score for an entity
+ found in the result set.
- return 1 if the given registry and object is selectable using selector's
- input context, else 0
- """
- def __init__(self, registry, oid):
- self.registry = registry
- self.oid = oid
-
- def __call__(self, cls, req, rset, *args, **kwargs):
- try:
- cls.vreg.select_object(self.registry, self.oid, req, rset, *args, **kwargs)
- return 1
- except NoSelectableObject:
- return 0
+ See `EntitySelector` documentation for behaviour when row is not specified.
-
-# XXX not so basic selectors ######################################################
-
-@lltrace
-def etype_rtype_selector(cls, req, rset, row=None, col=0, **kwargs):
- """only check if the user has read access on the entity's type refered
- by the .etype attribute and on the relations's type refered by the
- .rtype attribute if set.
+ :param scorefunc: callable expected to take an entity as argument and to
+ return a score >= 0
"""
- schema = cls.schema
- perm = getattr(cls, 'require_permission', 'read')
- if hasattr(cls, 'etype'):
- eschema = schema.eschema(cls.etype)
- if not (eschema.has_perm(req, perm) or eschema.has_local_role(perm)):
- return 0
- if hasattr(cls, 'rtype'):
- rschema = schema.rschema(cls.rtype)
- if not (rschema.has_perm(req, perm) or rschema.has_local_role(perm)):
- return 0
- return 1
-
-@lltrace
-def has_related_entities(cls, req, rset, row=None, col=0, **kwargs):
- return bool(rset.get_entity(row or 0, col or 0).related(cls.rtype, role(cls)))
-
-@lltrace
-def user_can_add_etype(cls, req, rset, row=None, col=0, **kwargs):
- """only check if the user has add access on the entity's type refered
- by the .etype attribute.
- """
- if not cls.schema.eschema(cls.etype).has_perm(req, 'add'):
- return 0
- return 1
-add_etype_selector = deprecated_function(user_can_add_etype)
-
-@lltrace
-def match_context_prop(cls, req, rset, row=None, col=0, context=None,
- **kwargs):
- propval = req.property_value('%s.%s.context' % (cls.__registry__, cls.id))
- if not propval:
- propval = cls.context
- if context is not None and propval and context != propval:
- return 0
- return 1
-contextprop_selector = deprecated_function(match_context_prop)
-
-@lltrace
-def primary_view(cls, req, rset, row=None, col=0, view=None, **kwargs):
- if view is not None and not view.is_primary():
- return 0
- return 1
-primaryview_selector = deprecated_function(primary_view)
-
+ def __init__(self, scorefunc):
+ self.score_entity = scorefunc
# XXX DEPRECATED ##############################################################
+yes_selector = deprecated_function(yes)
+norset_selector = deprecated_function(none_rset)
+rset_selector = deprecated_function(any_rset)
+anyrset_selector = deprecated_function(nonempty_rset)
+emptyrset_selector = deprecated_function(empty_rset)
+onelinerset_selector = deprecated_function(one_line_rset)
+twolinerset_selector = deprecated_function(two_lines_rset)
+twocolrset_selector = deprecated_function(two_cols_rset)
+largerset_selector = deprecated_function(paginated_rset)
+sortedrset_selector = deprecated_function(sorted_rset)
+oneetyperset_selector = deprecated_function(one_etype_rset)
+multitype_selector = deprecated_function(two_etypes_rset)
+anonymous_selector = deprecated_function(anonymous_user)
+not_anonymous_selector = deprecated_function(authenticated_user)
+primaryview_selector = deprecated_function(primary_view)
+contextprop_selector = deprecated_function(match_context_prop)
+
def nfentity_selector(cls, req, rset, row=None, col=0, **kwargs):
return non_final_entity()(cls, req, rset, row, col)
nfentity_selector = deprecated_function(nfentity_selector)
@@ -789,6 +864,24 @@
return but_etype(cls.etype)(cls, req, rset, row, col)
but_etype_selector = deprecated_function(but_etype_selector)
+@lltrace
+def etype_rtype_selector(cls, req, rset, row=None, col=0, **kwargs):
+ """only check if the user has read access on the entity's type refered
+ by the .etype attribute and on the relations's type refered by the
+ .rtype attribute if set.
+ """
+ schema = cls.schema
+ perm = getattr(cls, 'require_permission', 'read')
+ if hasattr(cls, 'etype'):
+ eschema = schema.eschema(cls.etype)
+ if not (eschema.has_perm(req, perm) or eschema.has_local_role(perm)):
+ return 0
+ if hasattr(cls, 'rtype'):
+ rschema = schema.rschema(cls.rtype)
+ if not (rschema.has_perm(req, perm) or rschema.has_local_role(perm)):
+ return 0
+ return 1
+etype_rtype_selector = deprecated_function(etype_rtype_selector)
#req_form_params_selector = deprecated_function(match_form_params) # form_params
#kwargs_selector = deprecated_function(match_kwargs) # expected_kwargs
@@ -804,10 +897,8 @@
name='searchstate_accept_one')
searchstate_accept_one_selector = deprecated_function(searchstate_accept_one)
-searchstate_accept_one_but_etype = chainall(searchstate_accept_one, but_etype,
- name='searchstate_accept_one_but_etype')
-searchstate_accept_one_but_etype_selector = deprecated_function(
- searchstate_accept_one_but_etype)
+searchstate_accept = deprecated_function(searchstate_accept)
+searchstate_accept_one = deprecated_function(searchstate_accept_one)
def require_group_compat(registered):