reldefsecurity branch :
* follow yams default branch api changes
* now consider permissions on relation definitions, not relation types.
This is still experimental.
--- a/devtools/_apptest.py Wed Nov 18 09:16:38 2009 +0100
+++ b/devtools/_apptest.py Thu Nov 19 12:55:47 2009 +0100
@@ -92,7 +92,7 @@
schema = self.vreg.schema
# else we may run into problems since email address are ususally share in app tests
# XXX should not be necessary anymore
- schema.rschema('primary_email').set_rproperty('CWUser', 'EmailAddress', 'composite', False)
+ schema.rschema('primary_email').rdef('CWUser', 'EmailAddress').composite = False
self.deletable_entities = unprotected_entities(schema)
def restore_database(self):
--- a/entity.py Wed Nov 18 09:16:38 2009 +0100
+++ b/entity.py Thu Nov 19 12:55:47 2009 +0100
@@ -34,7 +34,7 @@
def greater_card(rschema, subjtypes, objtypes, index):
for subjtype in subjtypes:
for objtype in objtypes:
- card = rschema.rproperty(subjtype, objtype, 'cardinality')[index]
+ card = rschema.rdef(subjtype, objtype).cardinality[index]
if card in '+*':
return card
return '1'
@@ -243,7 +243,8 @@
cls.warning('skipping fetch_attr %s defined in %s (not found in schema)',
attr, cls.id)
continue
- if not user.matching_groups(rschema.get_groups('read')):
+ rdef = eschema.rdef(attr)
+ if not user.matching_groups(rdef.get_groups('read')):
continue
var = varmaker.next()
selection.append(var)
@@ -252,7 +253,7 @@
if not rschema.final:
# XXX this does not handle several destination types
desttype = rschema.objects(eschema.type)[0]
- card = rschema.rproperty(eschema, desttype, 'cardinality')[0]
+ card = rdef.cardinality[0]
if card not in '?1':
cls.warning('bad relation %s specified in fetch attrs for %s',
attr, cls)
@@ -362,10 +363,10 @@
self.req.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None)
def check_perm(self, action):
- self.e_schema.check_perm(self.req, action, self.eid)
+ self.e_schema.check_perm(self.req, action, eid=self.eid)
def has_perm(self, action):
- return self.e_schema.has_perm(self.req, action, self.eid)
+ return self.e_schema.has_perm(self.req, action, eid=self.eid)
def view(self, vid, __registry='views', **kwargs):
"""shortcut to apply a view on this entity"""
@@ -443,11 +444,11 @@
return u''
if attrtype is None:
attrtype = self.e_schema.destination(attr)
- props = self.e_schema.rproperties(attr)
+ props = self.e_schema.rdef(attr)
if attrtype == 'String':
# internalinalized *and* formatted string such as schema
# description...
- if props.get('internationalizable'):
+ if props.internationalizable:
value = self.req._(value)
attrformat = self.attr_metadata(attr, 'format')
if attrformat:
@@ -495,11 +496,12 @@
if rschema.type in self.skip_copy_for:
continue
# skip composite relation
- if self.e_schema.subjrproperty(rschema, 'composite'):
+ rdef = self.e_schema.rdef(rschema)
+ if rdef.composite:
continue
# skip relation with card in ?1 else we either change the copied
# object (inlined relation) or inserting some inconsistency
- if self.e_schema.subjrproperty(rschema, 'cardinality')[1] in '?1':
+ if rdef.cardinality[1] in '?1':
continue
rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % (
rschema.type, rschema.type)
@@ -509,14 +511,15 @@
if rschema.meta:
continue
# skip already defined relations
- if getattr(self, 'reverse_%s' % rschema.type):
+ if self.related(rschema.type, 'object'):
continue
+ rdef = self.e_schema.rdef(rschema, 'object')
# skip composite relation
- if self.e_schema.objrproperty(rschema, 'composite'):
+ if rdef.composite:
continue
# skip relation with card in ?1 else we either change the copied
# object (inlined relation) or inserting some inconsistency
- if self.e_schema.objrproperty(rschema, 'cardinality')[0] in '?1':
+ if rdef.cardinality[0] in '?1':
continue
rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % (
rschema.type, rschema.type)
@@ -537,15 +540,16 @@
for rschema in self.e_schema.subject_relations():
if rschema.final:
continue
- if len(rschema.objects(self.e_schema)) > 1:
+ targets = rschema.objects(self.e_schema)
+ if len(targets) > 1:
# ambigous relations, the querier doesn't handle
# outer join correctly in this case
continue
if rschema.inlined:
+ rdef = rschema.rdef(self.e_schema, targets[0])
matching_groups = self.req.user.matching_groups
- if matching_groups(rschema.get_groups('read')) and \
- all(matching_groups(es.get_groups('read'))
- for es in rschema.objects(self.e_schema)):
+ if matching_groups(rdef.get_groups('read')) and \
+ all(matching_groups(e.get_groups('read')) for e in targets):
yield rschema, 'subject'
def to_complete_attributes(self, skip_bytes=True):
@@ -557,7 +561,8 @@
if attr == 'eid':
continue
# password retreival is blocked at the repository server level
- if not self.req.user.matching_groups(rschema.get_groups('read')) \
+ rdef = rschema.rdef(self.e_schema, attrschema)
+ if not self.req.user.matching_groups(rdef.get_groups('read')) \
or attrschema.type == 'Password':
self[attr] = None
continue
@@ -593,24 +598,21 @@
if self.relation_cached(rtype, role):
continue
var = varmaker.next()
+ targettype = rschema.targets(self.e_schema, role)[0]
+ rdef = rschema.role_rdef(self.e_schema, targettype, role)
+ card = rdef.role_cardinality(role)
+ assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype,
+ role, card)
if role == 'subject':
- targettype = rschema.objects(self.e_schema)[0]
- card = rschema.rproperty(self.e_schema, targettype,
- 'cardinality')[0]
if card == '1':
rql.append('%s %s %s' % (V, rtype, var))
- else: # '?"
+ else:
rql.append('%s %s %s?' % (V, rtype, var))
else:
- targettype = rschema.subjects(self.e_schema)[1]
- card = rschema.rproperty(self.e_schema, targettype,
- 'cardinality')[1]
if card == '1':
rql.append('%s %s %s' % (var, rtype, V))
- else: # '?"
+ else:
rql.append('%s? %s %s' % (var, rtype, V))
- assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype,
- role, card)
selected.append(((rtype, role), var))
if selected:
# select V, we need it as the left most selected variable
@@ -756,16 +758,16 @@
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')
+ rdef = rtype.role_rdef(self.e_schema, targettype, role)
+ insertsecurity = (rdef.has_local_role('add') and not
+ rdef.has_perm(self.req, 'add', **securitycheck_args))
if vocabconstraints:
# RQLConstraint is a subclass for RQLVocabularyConstraint, so they
# will be included as well
- restriction += [cstr.restriction for cstr in constraints
+ restriction += [cstr.restriction for cstr in rdef.constraints
if isinstance(cstr, RQLVocabularyConstraint)]
else:
- restriction += [cstr.restriction for cstr in constraints
+ restriction += [cstr.restriction for cstr in rdef.constraints
if isinstance(cstr, RQLConstraint)]
etypecls = self.vreg['etypes'].etype_class(targettype)
rql = etypecls.fetch_rql(self.req.user, restriction,
@@ -775,7 +777,7 @@
before, after = rql.split(' WHERE ', 1)
rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
if insertsecurity:
- rqlexprs = rtype.get_rqlexprs('add')
+ rqlexprs = rdef.get_rqlexprs('add')
rewriter = RQLRewriter(self.req)
rqlst = self.req.vreg.parse(self.req, rql, args)
if not self.has_eid():
@@ -827,12 +829,10 @@
related = tuple(rset.entities(col))
rschema = self.schema.rschema(rtype)
if role == 'subject':
- rcard = rschema.rproperty(self.e_schema, related[0].e_schema,
- 'cardinality')[1]
+ rcard = rschema.rdef(self.e_schema, related[0].e_schema).cardinality[1]
target = 'object'
else:
- rcard = rschema.rproperty(related[0].e_schema, self.e_schema,
- 'cardinality')[0]
+ rcard = rschema.rdef(related[0].e_schema, self.e_schema).cardinality[0]
target = 'subject'
if rcard in '?1':
for rentity in related:
--- a/rqlrewrite.py Wed Nov 18 09:16:38 2009 +0100
+++ b/rqlrewrite.py Thu Nov 19 12:55:47 2009 +0100
@@ -402,12 +402,12 @@
orel = self.varinfo['lhs_rels'][sniprel.r_type]
cardindex = 0
ttypes_func = rschema.objects
- rprop = rschema.rproperty
+ rdef = rschema.rdef
else: # target == 'subject':
orel = self.varinfo['rhs_rels'][sniprel.r_type]
cardindex = 1
ttypes_func = rschema.subjects
- rprop = lambda x, y, z: rschema.rproperty(y, x, z)
+ rdef = lambda x, y: rschema.rdef(y, x)
except KeyError, ex:
# may be raised by self.varinfo['xhs_rels'][sniprel.r_type]
return None
@@ -419,7 +419,7 @@
# variable from the original query
for etype in self.varinfo['stinfo']['possibletypes']:
for ttype in ttypes_func(etype):
- if rprop(etype, ttype, 'cardinality')[cardindex] in '+*':
+ if rdef(etype, ttype).cardinality[cardindex] in '+*':
return None
return orel
--- a/rset.py Wed Nov 18 09:16:38 2009 +0100
+++ b/rset.py Thu Nov 19 12:55:47 2009 +0100
@@ -403,25 +403,22 @@
select = rqlst
# take care, due to outer join support, we may find None
# values for non final relation
- for i, attr, x in attr_desc_iterator(select, col):
+ for i, attr, role in attr_desc_iterator(select, col):
outerselidx = rqlst.subquery_selection_index(select, i)
if outerselidx is None:
continue
- if x == 'subject':
+ if role == 'subject':
rschema = eschema.subjrels[attr]
if rschema.final:
entity[attr] = rowvalues[outerselidx]
continue
- tetype = rschema.objects(etype)[0]
- card = rschema.rproperty(etype, tetype, 'cardinality')[0]
else:
rschema = eschema.objrels[attr]
- tetype = rschema.subjects(etype)[0]
- card = rschema.rproperty(tetype, etype, 'cardinality')[1]
+ rdef = eschema.rdef(attr, role)
# only keep value if it can't be multivalued
- if card in '1?':
+ if rdef.role_cardinality(role) in '1?':
if rowvalues[outerselidx] is None:
- if x == 'subject':
+ if role == 'subject':
rql = 'Any Y WHERE X %s Y, X eid %s'
else:
rql = 'Any Y WHERE Y %s X, X eid %s'
@@ -429,7 +426,7 @@
req.decorate_rset(rrset)
else:
rrset = self._build_entity(row, outerselidx).as_rset()
- entity.set_related_cache(attr, x, rrset)
+ entity.set_related_cache(attr, role, rrset)
return entity
@cached
--- a/schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -20,7 +20,8 @@
from logilab.common.compat import any
from yams import BadSchemaDefinition, buildobjs as ybo
-from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema
+from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema, \
+ RelationDefinitionSchema, PermissionMixIn
from yams.constraints import (BaseConstraint, StaticVocabularyConstraint,
FormatConstraint)
from yams.reader import (CONSTRAINTS, PyFileReader, SchemaLoader,
@@ -127,7 +128,7 @@
ERSchema.display_name = ERSchema_display_name
@cached
-def ERSchema_get_groups(self, action):
+def get_groups(self, action):
"""return the groups authorized to perform <action> on entities of
this type
@@ -140,28 +141,13 @@
assert action in self.ACTIONS, action
#assert action in self._groups, '%s %s' % (self, action)
try:
- return frozenset(g for g in self._groups[action] if isinstance(g, basestring))
+ return frozenset(g for g in self.permissions[action] if isinstance(g, basestring))
except KeyError:
return ()
-ERSchema.get_groups = ERSchema_get_groups
-
-def ERSchema_set_groups(self, action, groups):
- """set the groups allowed to perform <action> on entities of this type. Don't
- change rql expressions for the same action.
-
- :type action: str
- :param action: the name of a permission
-
- :type groups: list or tuple
- :param groups: names of the groups granted to do the given action
- """
- assert action in self.ACTIONS, action
- clear_cache(self, 'ERSchema_get_groups')
- self._groups[action] = tuple(groups) + self.get_rqlexprs(action)
-ERSchema.set_groups = ERSchema_set_groups
+PermissionMixIn.get_groups = get_groups
@cached
-def ERSchema_get_rqlexprs(self, action):
+def get_rqlexprs(self, action):
"""return the rql expressions representing queries to check the user is allowed
to perform <action> on entities of this type
@@ -174,27 +160,13 @@
assert action in self.ACTIONS, action
#assert action in self._rqlexprs, '%s %s' % (self, action)
try:
- return tuple(g for g in self._groups[action] if not isinstance(g, basestring))
+ return tuple(g for g in self.permissions[action] if not isinstance(g, basestring))
except KeyError:
return ()
-ERSchema.get_rqlexprs = ERSchema_get_rqlexprs
-
-def ERSchema_set_rqlexprs(self, action, rqlexprs):
- """set the rql expression allowing to perform <action> on entities of this type. Don't
- change groups for the same action.
-
- :type action: str
- :param action: the name of a permission
+PermissionMixIn.get_rqlexprs = get_rqlexprs
- :type rqlexprs: list or tuple
- :param rqlexprs: the rql expressions allowing the given action
- """
- assert action in self.ACTIONS, action
- clear_cache(self, 'ERSchema_get_rqlexprs')
- self._groups[action] = tuple(self.get_groups(action)) + tuple(rqlexprs)
-ERSchema.set_rqlexprs = ERSchema_set_rqlexprs
-
-def ERSchema_set_permissions(self, action, permissions):
+orig_set_action_permissions = PermissionMixIn.set_action_permissions
+def set_action_permissions(self, action, permissions):
"""set the groups and rql expressions allowing to perform <action> on
entities of this type
@@ -204,22 +176,12 @@
:type permissions: tuple
:param permissions: the groups and rql expressions allowing the given action
"""
- assert action in self.ACTIONS, action
- clear_cache(self, 'ERSchema_get_rqlexprs')
- clear_cache(self, 'ERSchema_get_groups')
- self._groups[action] = tuple(permissions)
-ERSchema.set_permissions = ERSchema_set_permissions
+ orig_set_action_permissions(self, action, tuple(permissions))
+ clear_cache(self, 'get_rqlexprs')
+ clear_cache(self, 'get_groups')
+PermissionMixIn.set_action_permissions = set_action_permissions
-def ERSchema_has_perm(self, session, action, *args, **kwargs):
- """return true if the action is granted globaly or localy"""
- try:
- self.check_perm(session, action, *args, **kwargs)
- return True
- except Unauthorized:
- return False
-ERSchema.has_perm = ERSchema_has_perm
-
-def ERSchema_has_local_role(self, action):
+def has_local_role(self, action):
"""return true if the action *may* be granted localy (eg either rql
expressions or the owners group are used in security definition)
@@ -230,9 +192,83 @@
if self.get_rqlexprs(action):
return True
if action in ('update', 'delete'):
- return self.has_group(action, 'owners')
+ return 'owners' in self.get_groups(action)
return False
-ERSchema.has_local_role = ERSchema_has_local_role
+PermissionMixIn.has_local_role = has_local_role
+
+def may_have_permission(self, action, req):
+ if action != 'read' and not (self.has_local_role('read') or
+ self.has_perm(req, 'read')):
+ return False
+ return self.has_local_role(action) or self.has_perm(req, action)
+PermissionMixIn.may_have_permission = may_have_permission
+
+def has_perm(self, session, action, **kwargs):
+ """return true if the action is granted globaly or localy"""
+ try:
+ self.check_perm(session, action, **kwargs)
+ return True
+ except Unauthorized:
+ return False
+PermissionMixIn.has_perm = has_perm
+
+def check_perm(self, session, action, **kwargs):
+ # NB: session may be a server session or a request object check user is
+ # in an allowed group, if so that's enough internal sessions should
+ # always stop there
+ groups = self.get_groups(action)
+ if session.user.matching_groups(groups):
+ return
+ # if 'owners' in allowed groups, check if the user actually owns this
+ # object, if so that's enough
+ if 'owners' in groups and 'eid' in kwargs and session.user.owns(kwargs['eid']):
+ return
+ # else if there is some rql expressions, check them
+ if any(rqlexpr.check(session, **kwargs)
+ for rqlexpr in self.get_rqlexprs(action)):
+ return
+ raise Unauthorized(action, str(self))
+PermissionMixIn.check_perm = check_perm
+
+
+RelationDefinitionSchema._RPROPERTIES['eid'] = None
+
+def rql_expression(self, expression, mainvars=None, eid=None):
+ """rql expression factory"""
+ if self.rtype.final:
+ return ERQLExpression(expression, mainvars, eid)
+ return RRQLExpression(expression, mainvars, eid)
+RelationDefinitionSchema.rql_expression = rql_expression
+
+orig_check_permission_definitions = RelationDefinitionSchema.check_permission_definitions
+def check_permission_definitions(self):
+ orig_check_permission_definitions(self)
+ schema = self.subject.schema
+ for action, groups in self.permissions.iteritems():
+ for group_or_rqlexpr in groups:
+ if action == 'read' and \
+ isinstance(group_or_rqlexpr, RQLExpression):
+ msg = "can't use rql expression for read permission of %s"
+ raise BadSchemaDefinition(msg % self)
+ elif self.final and isinstance(group_or_rqlexpr, RRQLExpression):
+ if schema.reading_from_database:
+ # we didn't have final relation earlier, so turn
+ # RRQLExpression into ERQLExpression now
+ rqlexpr = group_or_rqlexpr
+ newrqlexprs = [x for x in self.get_rqlexprs(action)
+ if not x is rqlexpr]
+ newrqlexprs.append(ERQLExpression(rqlexpr.expression,
+ rqlexpr.mainvars,
+ rqlexpr.eid))
+ self.set_rqlexprs(action, newrqlexprs)
+ else:
+ msg = "can't use RRQLExpression on %s, use an ERQLExpression"
+ raise BadSchemaDefinition(msg % self)
+ elif not self.final and \
+ isinstance(group_or_rqlexpr, ERQLExpression):
+ msg = "can't use ERQLExpression on %s, use a RRQLExpression"
+ raise BadSchemaDefinition(msg % self)
+RelationDefinitionSchema.check_permission_definitions = check_permission_definitions
def system_etypes(schema):
@@ -256,8 +292,8 @@
eid = getattr(edef, 'eid', None)
self.eid = eid
# take care: no _groups attribute when deep-copying
- if getattr(self, '_groups', None):
- for groups in self._groups.itervalues():
+ if getattr(self, 'permissions', None):
+ for groups in self.permissions.itervalues():
for group_or_rqlexpr in groups:
if isinstance(group_or_rqlexpr, RRQLExpression):
msg = "can't use RRQLExpression on an entity type, use an ERQLExpression (%s)"
@@ -304,7 +340,7 @@
if rschema.final:
if rschema == 'has_text':
has_has_text = True
- elif self.rproperty(rschema, 'fulltextindexed'):
+ elif self.rdef(rschema).get('fulltextindexed'):
may_need_has_text = True
elif rschema.fulltext_container:
if rschema.fulltext_container == 'subject':
@@ -329,32 +365,12 @@
"""return True if this entity type is used to build the schema"""
return self.type in SCHEMA_TYPES
- def check_perm(self, session, action, eid=None):
- # NB: session may be a server session or a request object
- user = session.user
- # check user is in an allowed group, if so that's enough
- # internal sessions should always stop there
- if user.matching_groups(self.get_groups(action)):
- return
- # if 'owners' in allowed groups, check if the user actually owns this
- # object, if so that's enough
- if eid is not None and 'owners' in self.get_groups(action) and \
- user.owns(eid):
- return
- # else if there is some rql expressions, check them
- if any(rqlexpr.check(session, eid)
- for rqlexpr in self.get_rqlexprs(action)):
- return
- raise Unauthorized(action, str(self))
-
def rql_expression(self, expression, mainvars=None, eid=None):
"""rql expression factory"""
return ERQLExpression(expression, mainvars, eid)
class CubicWebRelationSchema(RelationSchema):
- RelationSchema._RPROPERTIES['eid'] = None
- _perms_checked = False
def __init__(self, schema=None, rdef=None, eid=None, **kwargs):
if rdef is not None:
@@ -369,73 +385,52 @@
def meta(self):
return self.type in META_RTYPES
- def update(self, subjschema, objschema, rdef):
- super(CubicWebRelationSchema, self).update(subjschema, objschema, rdef)
- if not self._perms_checked and self._groups:
- for action, groups in self._groups.iteritems():
- for group_or_rqlexpr in groups:
- if action == 'read' and \
- isinstance(group_or_rqlexpr, RQLExpression):
- msg = "can't use rql expression for read permission of "\
- "a relation type (%s)"
- raise BadSchemaDefinition(msg % self.type)
- elif self.final and isinstance(group_or_rqlexpr, RRQLExpression):
- if self.schema.reading_from_database:
- # we didn't have final relation earlier, so turn
- # RRQLExpression into ERQLExpression now
- rqlexpr = group_or_rqlexpr
- newrqlexprs = [x for x in self.get_rqlexprs(action) if not x is rqlexpr]
- newrqlexprs.append(ERQLExpression(rqlexpr.expression,
- rqlexpr.mainvars,
- rqlexpr.eid))
- self.set_rqlexprs(action, newrqlexprs)
- else:
- msg = "can't use RRQLExpression on a final relation "\
- "type (eg attribute relation), use an ERQLExpression (%s)"
- raise BadSchemaDefinition(msg % self.type)
- elif not self.final and \
- isinstance(group_or_rqlexpr, ERQLExpression):
- msg = "can't use ERQLExpression on a relation type, use "\
- "a RRQLExpression (%s)"
- raise BadSchemaDefinition(msg % self.type)
- self._perms_checked = True
-
- def cardinality(self, subjtype, objtype, target):
- card = self.rproperty(subjtype, objtype, 'cardinality')
- return (target == 'subject' and card[0]) or \
- (target == 'object' and card[1])
-
def schema_relation(self):
"""return True if this relation type is used to build the schema"""
return self.type in SCHEMA_TYPES
- def physical_mode(self):
- """return an appropriate mode for physical storage of this relation type:
- * 'subjectinline' if every possible subject cardinalities are 1 or ?
- * 'objectinline' if 'subjectinline' mode is not possible but every
- possible object cardinalities are 1 or ?
- * None if neither 'subjectinline' and 'objectinline'
- """
- assert not self.final
- return self.inlined and 'subjectinline' or None
+ def may_have_permission(self, action, req, eschema=None, role=None):
+ if eschema is not None:
+ for tschema in rschema.targets(eschema, role):
+ rdef = rschema.role_rdef(eschema, tschema, role)
+ if rdef.may_have_permission(action, req):
+ return True
+ else:
+ for rdef in self.rdefs.itervalues():
+ if rdef.may_have_permission(action, req):
+ return True
+ return False
- def check_perm(self, session, action, *args, **kwargs):
- # NB: session may be a server session or a request object check user is
- # in an allowed group, if so that's enough internal sessions should
- # always stop there
- if session.user.matching_groups(self.get_groups(action)):
- return
- # else if there is some rql expressions, check them
- if any(rqlexpr.check(session, *args, **kwargs)
- for rqlexpr in self.get_rqlexprs(action)):
- return
- raise Unauthorized(action, str(self))
+ def has_perm(self, session, action, **kwargs):
+ """return true if the action is granted globaly or localy"""
+ if 'fromeid' in kwargs:
+ subjtype = session.describe(kwargs['fromeid'])
+ else:
+ subjtype = None
+ if 'toeid' in kwargs:
+ objtype = session.describe(kwargs['toeid'])
+ else:
+ objtype = Nono
+ if objtype and subjtype:
+ return self.rdef(subjtype, objtype).has_perm(session, action, **kwargs)
+ elif subjtype:
+ for tschema in rschema.targets(subjtype, 'subject'):
+ rdef = rschema.rdef(subjtype, tschema)
+ if not rdef.has_perm(action, req, **kwargs):
+ return False
+ elif objtype:
+ for tschema in rschema.targets(objtype, 'object'):
+ rdef = rschema.rdef(tschema, objtype)
+ if not rdef.has_perm(action, req, **kwargs):
+ return False
+ else:
+ for rdef in self.rdefs.itervalues():
+ if not rdef.has_perm(action, req, **kwargs):
+ return False
- def rql_expression(self, expression, mainvars=None, eid=None):
- """rql expression factory"""
- if self.final:
- return ERQLExpression(expression, mainvars, eid)
- return RRQLExpression(expression, mainvars, eid)
+ @deprecated('use .rdef(subjtype, objtype).role_cardinality(role)')
+ def cardinality(self, subjtype, objtype, target):
+ return self.rdef(subjtype, objtype).role_cardinality(target)
class CubicWebSchema(Schema):
@@ -460,13 +455,10 @@
ybo.register_base_types(self)
rschema = self.add_relation_type(ybo.RelationType('eid'))
rschema.final = True
- rschema.set_default_groups()
rschema = self.add_relation_type(ybo.RelationType('has_text'))
rschema.final = True
- rschema.set_default_groups()
rschema = self.add_relation_type(ybo.RelationType('identity'))
rschema.final = False
- rschema.set_default_groups()
def add_entity_type(self, edef):
edef.name = edef.name.encode()
@@ -508,11 +500,10 @@
rdef.name = rdef.name.lower()
rdef.subject = bw_normalize_etype(rdef.subject)
rdef.object = bw_normalize_etype(rdef.object)
- if super(CubicWebSchema, self).add_relation_def(rdef):
+ rdefs = super(CubicWebSchema, self).add_relation_def(rdef)
+ if rdefs:
try:
- self._eid_index[rdef.eid] = (self.eschema(rdef.subject),
- self.rschema(rdef.name),
- self.eschema(rdef.object))
+ self._eid_index[rdef.eid] = rdefs
except AttributeError:
pass # not a serialized schema
@@ -523,7 +514,9 @@
def del_relation_def(self, subjtype, rtype, objtype):
for k, v in self._eid_index.items():
- if v == (subjtype, rtype, objtype):
+ if not isinstance(v, RelationDefinitionSchema):
+ continue
+ if v.subject == subjtype and v.rtype == rtype and v.object == objtype:
del self._eid_index[k]
break
super(CubicWebSchema, self).del_relation_def(subjtype, rtype, objtype)
@@ -654,6 +647,11 @@
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self.full_rql)
+ def __cmp__(self, other):
+ if hasattr(other, 'expression'):
+ return cmp(other.expression, self.expression)
+ return False
+
def __deepcopy__(self, memo):
return self.__class__(self.expression, self.mainvars)
def __getstate__(self):
@@ -755,7 +753,7 @@
for eaction, var, col in has_perm_defs:
for i in xrange(len(rset)):
eschema = get_eschema(rset.description[i][col])
- eschema.check_perm(session, eaction, rset[i][col])
+ eschema.check_perm(session, eaction, eid=rset[i][col])
if self.eid is not None:
session.local_perm_cache[key] = True
return True
--- a/schemas/Bookmark.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schemas/Bookmark.py Thu Nov 19 12:55:47 2009 +0100
@@ -13,7 +13,7 @@
class Bookmark(EntityType):
"""bookmarks are used to have user's specific internal links"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', 'users',),
'delete': ('managers', 'owners',),
@@ -29,7 +29,7 @@
class bookmarked_by(RelationType):
- permissions = {'read': ('managers', 'users', 'guests',),
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
# test user in users group to avoid granting permission to anonymous user
'add': ('managers', RRQLExpression('O identity U, U in_group G, G name "users"')),
'delete': ('managers', RRQLExpression('O identity U, U in_group G, G name "users"')),
--- a/schemas/base.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schemas/base.py Thu Nov 19 12:55:47 2009 +0100
@@ -16,7 +16,7 @@
class CWUser(WorkflowableEntityType):
"""define a CubicWeb user"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', ERQLExpression('X identity U')),
'add': ('managers',),
'delete': ('managers',),
@@ -37,12 +37,12 @@
in_group = SubjectRelation('CWGroup', cardinality='+*',
constraints=[RQLConstraint('NOT O name "owners"')],
- description=_('groups grant permissions to the user'))
+ description=_('groups grant __permissions__ to the user'))
class EmailAddress(EntityType):
"""an electronic mail address associated to a short alias"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',), # XXX if P use_email X, U has_read_permission P
'add': ('managers', 'users',),
'delete': ('managers', 'owners', ERQLExpression('P use_email X, U has_update_permission P')),
@@ -59,7 +59,7 @@
class use_email(RelationType):
""" """
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', RRQLExpression('U has_update_permission S'),),
'delete': ('managers', RRQLExpression('U has_update_permission S'),),
@@ -68,12 +68,12 @@
class primary_email(RelationType):
"""the prefered email"""
- permissions = use_email.permissions
+ __permissions__ = use_email.__permissions__
class prefered_form(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
- # XXX should have update permissions on both subject and object,
+ # XXX should have update __permissions__ on both subject and object,
# though by doing this we will probably have no way to add
# this relation in the web ui. The easiest way to acheive this
# is probably to be able to have "U has_update_permission O" as
@@ -85,13 +85,13 @@
class in_group(RelationType):
"""core relation indicating a user's groups"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class owned_by(RelationType):
"""core relation indicating owners of an entity. This relation
implicitly put the owner into the owners group for the entity
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', RRQLExpression('S owned_by U'),),
'delete': ('managers', RRQLExpression('S owned_by U'),),
@@ -104,7 +104,7 @@
class created_by(RelationType):
"""core relation indicating the original creator of an entity"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'delete': ('managers',),
@@ -139,7 +139,7 @@
"""used for cubicweb configuration. Once a property has been created you
can't change the key.
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', 'users',),
'update': ('managers', 'owners',),
@@ -163,7 +163,7 @@
"""link a property to the user which want this property customization. Unless
you're a site manager, this relation will be handled automatically.
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'delete': ('managers',),
@@ -174,7 +174,7 @@
class CWPermission(EntityType):
"""entity type that may be used to construct some advanced security configuration
"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True, maxsize=100,
description=_('name or identifier of the permission'))
@@ -189,7 +189,7 @@
"""link a permission to the entity. This permission should be used in the
security definition of the entity's type to be useful.
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'delete': ('managers',),
@@ -197,7 +197,7 @@
class require_group(RelationType):
"""used to grant a permission to a group"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'delete': ('managers',),
@@ -217,7 +217,7 @@
NOTE: You'll have to explicitly declare which entity types can have a
same_as relation
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', 'users'),
'delete': ('managers', 'owners'),
@@ -237,7 +237,7 @@
Also, checkout the AppObject.get_cache() method.
"""
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'update': ('managers', 'users',), # XXX
@@ -254,9 +254,9 @@
class identical_to(RelationType):
"""identical to"""
symetric = True
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
- # XXX should have update permissions on both subject and object,
+ # XXX should have update __permissions__ on both subject and object,
# though by doing this we will probably have no way to add
# this relation in the web ui. The easiest way to acheive this
# is probably to be able to have "U has_update_permission O" as
@@ -269,7 +269,7 @@
class see_also(RelationType):
"""generic relation to link one entity to another"""
symetric = True
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', RRQLExpression('U has_update_permission S'),),
'delete': ('managers', RRQLExpression('U has_update_permission S'),),
--- a/schemas/bootstrap.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schemas/bootstrap.py Thu Nov 19 12:55:47 2009 +0100
@@ -17,7 +17,7 @@
# access to this
class CWEType(EntityType):
"""define an entity type, used to build the instance schema"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
description = RichString(internationalizable=True,
@@ -28,7 +28,7 @@
class CWRType(EntityType):
"""define a relation type, used to build the instance schema"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
description = RichString(internationalizable=True,
@@ -48,7 +48,7 @@
used to build the instance schema
"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
relation_type = SubjectRelation('CWRType', cardinality='1*',
constraints=[RQLConstraint('O final TRUE')],
composite='object')
@@ -85,7 +85,7 @@
used to build the instance schema
"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
relation_type = SubjectRelation('CWRType', cardinality='1*',
constraints=[RQLConstraint('O final FALSE')],
composite='object')
@@ -115,8 +115,8 @@
# not restricted since it has to be read when checking allowed transitions
class RQLExpression(EntityType):
- """define a rql expression used to define permissions"""
- permissions = META_ETYPE_PERMS
+ """define a rql expression used to define __permissions__"""
+ __permissions__ = META_ETYPE_PERMS
exprtype = String(required=True, vocabulary=['ERQLExpression', 'RRQLExpression'])
mainvars = String(maxsize=8,
description=_('name of the main variables which should be '
@@ -131,11 +131,11 @@
'relation\'subject, object and to '
'the request user. '))
- read_permission = ObjectRelation(('CWEType', 'CWRType'), cardinality='+?', composite='subject',
+ read_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='+?', composite='subject',
description=_('rql expression allowing to read entities/relations of this type'))
- add_permission = ObjectRelation(('CWEType', 'CWRType'), cardinality='*?', composite='subject',
+ add_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='*?', composite='subject',
description=_('rql expression allowing to add entities/relations of this type'))
- delete_permission = ObjectRelation(('CWEType', 'CWRType'), cardinality='*?', composite='subject',
+ delete_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='*?', composite='subject',
description=_('rql expression allowing to delete entities/relations of this type'))
update_permission = ObjectRelation('CWEType', cardinality='*?', composite='subject',
description=_('rql expression allowing to update entities of this type'))
@@ -143,14 +143,14 @@
class CWConstraint(EntityType):
"""define a schema constraint"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
cstrtype = SubjectRelation('CWConstraintType', cardinality='1*')
value = String(description=_('depends on the constraint type'))
class CWConstraintType(EntityType):
"""define a schema constraint type"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
@@ -158,15 +158,15 @@
# not restricted since it has to be read when checking allowed transitions
class CWGroup(EntityType):
"""define a CubicWeb users group"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
unique=True, maxsize=64)
- read_permission = ObjectRelation(('CWEType', 'CWRType'), cardinality='+*',
+ read_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'), cardinality='+*',
description=_('groups allowed to read entities/relations of this type'))
- add_permission = ObjectRelation(('CWEType', 'CWRType'),
+ add_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'),
description=_('groups allowed to add entities/relations of this type'))
- delete_permission = ObjectRelation(('CWEType', 'CWRType'),
+ delete_permission = ObjectRelation(('CWEType', 'CWAttribute', 'CWRelation'),
description=_('groups allowed to delete entities/relations of this type'))
update_permission = ObjectRelation('CWEType',
description=_('groups allowed to update entities of this type'))
@@ -175,50 +175,50 @@
class relation_type(RelationType):
"""link a relation definition to its relation type"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class from_entity(RelationType):
"""link a relation definition to its subject entity type"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class to_entity(RelationType):
"""link a relation definition to its object entity type"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class constrained_by(RelationType):
"""constraints applying on this relation"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class cstrtype(RelationType):
"""constraint factory"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class read_permission(RelationType):
"""core relation giving to a group the permission to read an entity or
relation type
"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class add_permission(RelationType):
"""core relation giving to a group the permission to add an entity or
relation type
"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class delete_permission(RelationType):
"""core relation giving to a group the permission to delete an entity or
relation type
"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class update_permission(RelationType):
"""core relation giving to a group the permission to update an entity type
"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class is_(RelationType):
@@ -227,7 +227,7 @@
name = 'is'
# don't explicitly set composite here, this is handled anyway
#composite = 'object'
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': (),
'delete': (),
@@ -242,7 +242,7 @@
"""
# don't explicitly set composite here, this is handled anyway
#composite = 'object'
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': (),
'delete': (),
@@ -253,7 +253,7 @@
class specializes(RelationType):
name = 'specializes'
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers',),
'delete': ('managers',),
--- a/schemas/workflow.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schemas/workflow.py Thu Nov 19 12:55:47 2009 +0100
@@ -15,7 +15,7 @@
HOOKS_RTYPE_PERMS)
class Workflow(EntityType):
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
maxsize=256)
@@ -33,7 +33,7 @@
class default_workflow(RelationType):
"""default workflow for an entity type"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
subject = 'CWEType'
object = 'Workflow'
@@ -45,7 +45,7 @@
"""used to associate simple states to an entity type and/or to define
workflows
"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
maxsize=256)
@@ -64,7 +64,7 @@
class BaseTransition(EntityType):
"""abstract base class for transitions"""
- permissions = META_ETYPE_PERMS
+ __permissions__ = META_ETYPE_PERMS
name = String(required=True, indexed=True, internationalizable=True,
maxsize=256)
@@ -126,7 +126,7 @@
class TrInfo(EntityType):
"""workflow history item"""
# 'add' security actually done by hooks
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',), # XXX U has_read_permission O ?
'add': ('managers', 'users', 'guests',),
'delete': (), # XXX should we allow managers to delete TrInfo?
@@ -142,11 +142,11 @@
# get actor and date time using owned_by and creation_date
class from_state(RelationType):
- permissions = HOOKS_RTYPE_PERMS.copy()
+ __permissions__ = HOOKS_RTYPE_PERMS.copy()
inlined = True
class to_state(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers',),
'delete': (),
@@ -155,7 +155,7 @@
class by_transition(RelationType):
# 'add' security actually done by hooks
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', 'users', 'guests',),
'delete': (),
@@ -164,52 +164,52 @@
class workflow_of(RelationType):
"""link a workflow to one or more entity type"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class state_of(RelationType):
"""link a state to one or more workflow"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class transition_of(RelationType):
"""link a transition to one or more workflow"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class subworkflow(RelationType):
"""link a transition to one or more workflow"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class exit_point(RelationType):
"""link a transition to one or more workflow"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
class subworkflow_state(RelationType):
"""link a transition to one or more workflow"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class initial_state(RelationType):
"""indicate which state should be used by default when an entity using
states is created
"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class destination_state(RelationType):
"""destination state of a transition"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
inlined = True
class allowed_transition(RelationType):
"""allowed transition from this state"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
# "abstract" relations, set by WorkflowableEntityType ##########################
class custom_workflow(RelationType):
"""allow to set a specific workflow for an entity"""
- permissions = META_RTYPE_PERMS
+ __permissions__ = META_RTYPE_PERMS
cardinality = '?*'
constraints = [RQLConstraint('S is ET, O workflow_of ET')]
@@ -219,7 +219,7 @@
class wf_info_for(RelationType):
"""link a transition information to its object"""
# 'add' security actually done by hooks
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests',),
'add': ('managers', 'users', 'guests',),
'delete': (),
@@ -234,7 +234,7 @@
class in_state(RelationType):
"""indicate the current state of an entity"""
- permissions = HOOKS_RTYPE_PERMS
+ __permissions__ = HOOKS_RTYPE_PERMS
# not inlined intentionnaly since when using ldap sources, user'state
# has to be stored outside the CWUser table
--- a/schemaviewer.py Wed Nov 18 09:16:38 2009 +0100
+++ b/schemaviewer.py Thu Nov 19 12:55:47 2009 +0100
@@ -13,6 +13,7 @@
I18NSTRINGS = [_('read'), _('add'), _('delete'), _('update'), _('order')]
+
class SchemaViewer(object):
"""return an ureport layout for some part of a schema"""
def __init__(self, req=None, encoding=None):
@@ -68,7 +69,8 @@
_ = self.req._
data = [_('attribute'), _('type'), _('default'), _('constraints')]
for rschema, aschema in eschema.attribute_definitions():
- if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+ rdef = eschema.rdef(rschema)
+ if not rdef.may_have_permission('read', self.req):
continue
aname = rschema.type
if aname == 'eid':
@@ -78,7 +80,7 @@
defaultval = eschema.default(aname)
if defaultval is not None:
default = self.to_string(defaultval)
- elif eschema.rproperty(rschema, 'cardinality')[0] == '1':
+ elif rdef.cardinality[0] == '1':
default = _('required field')
else:
default = ''
@@ -119,20 +121,23 @@
t_vars = []
rels = []
first = True
- for rschema, targetschemas, x in eschema.relation_definitions():
+ for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.type in skiptypes:
continue
- if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
- continue
rschemaurl = self.rschema_link_url(rschema)
for oeschema in targetschemas:
+ rdef = rschema.role_rdef(eschema, oeschema, role)
+ if not rdef.may_have_permission('read', self.req):
+ continue
label = rschema.type
- if x == 'subject':
+ if role == 'subject':
cards = rschema.rproperty(eschema, oeschema, 'cardinality')
else:
cards = rschema.rproperty(oeschema, eschema, 'cardinality')
cards = cards[::-1]
- label = '%s %s (%s) %s' % (CARD_MAP[cards[1]], label, display_name(self.req, label, x), CARD_MAP[cards[0]])
+ label = '%s %s (%s) %s' % (CARD_MAP[cards[1]], label,
+ display_name(self.req, label, role),
+ CARD_MAP[cards[0]])
rlink = Link(rschemaurl, label)
elink = Link(self.eschema_link_url(oeschema), oeschema.type)
if first:
--- a/selectors.py Wed Nov 18 09:16:38 2009 +0100
+++ b/selectors.py Thu Nov 19 12:55:47 2009 +0100
@@ -665,19 +665,6 @@
self.target_etype = target_etype
self.action = action
- @lltrace
- def __call__(self, cls, req, *args, **kwargs):
- rschema = cls.schema.rschema(self.rtype)
- if not (rschema.has_perm(req, self.action)
- or rschema.has_local_role(self.action)):
- return 0
- if self.action != 'read':
- if not (rschema.has_perm(req, 'read')
- or rschema.has_local_role('read')):
- return 0
- score = super(relation_possible, self).__call__(cls, req, *args, **kwargs)
- return score
-
def score_class(self, eclass, req):
eschema = eclass.e_schema
try:
@@ -689,12 +676,13 @@
return 0
if self.target_etype is not None:
try:
- if self.role == 'subject':
- return int(self.target_etype in rschema.objects(eschema))
- else:
- return int(self.target_etype in rschema.subjects(eschema))
+ rdef = rschema.role_rdef(eschema, self.target_etype, self.role)
+ if not rdef.may_have_permission(self.action, req):
+ return 0
except KeyError:
return 0
+ else:
+ return rschema.may_have_permission(self.action, req, eschema, self.role)
return 1
@@ -1070,11 +1058,11 @@
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)):
+ if not eschema.may_have_permission(perm, req):
return 0
if hasattr(cls, 'rtype'):
rschema = schema.rschema(cls.rtype)
- if not (rschema.has_perm(req, perm) or rschema.has_local_role(perm)):
+ if not rschema.may_have_permission(perm, req):
return 0
return 1
etype_rtype_selector = deprecated()(etype_rtype_selector)
--- a/server/hookhelper.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/hookhelper.py Thu Nov 19 12:55:47 2009 +0100
@@ -27,7 +27,7 @@
rschema = session.repo.schema[rtype]
subjtype = session.describe(eidfrom)[0]
objtype = session.describe(eidto)[0]
- return rschema.rproperty(subjtype, objtype, rprop)
+ return getattr(rschema.rdef(subjtype, objtype), rprop)
def check_internal_entity(session, eid, internal_names):
"""check that the entity's name is not in the internal_names list.
--- a/server/hooks.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/hooks.py Thu Nov 19 12:55:47 2009 +0100
@@ -260,7 +260,7 @@
schema = session.vreg.schema
for attr in entity.edited_attributes:
if schema.rschema(attr).final:
- constraints = [c for c in entity.e_schema.constraints(attr)
+ constraints = [c for c in entity.e_schema.rdef(attr).constraints
if isinstance(c, RQLVocabularyConstraint)]
if constraints:
CheckConstraintsOperation(session, rdef=(entity.eid, attr, None),
@@ -317,22 +317,20 @@
if session.is_super_session:
return
eid = entity.eid
- for rschema, targetschemas, x in entity.e_schema.relation_definitions():
+ for rschema, targetschemas, role in entity.e_schema.relation_definitions():
# skip automatically handled relations
if rschema.type in DONT_CHECK_RTYPES_ON_ADD:
continue
- if x == 'subject':
+ if role == 'subject':
subjtype = entity.e_schema
objtype = targetschemas[0].type
- cardindex = 0
opcls = CheckSRelationOp
else:
subjtype = targetschemas[0].type
objtype = entity.e_schema
- cardindex = 1
opcls = CheckORelationOp
- card = rschema.rproperty(subjtype, objtype, 'cardinality')
- if card[cardindex] in '1+':
+ card = rschema.rdef(subjtype, objtype).role_cardinality(role)
+ if card in '1+':
checkrel_if_necessary(session, opcls, rschema.type, eid)
def cardinalitycheck_before_del_relation(session, eidfrom, rtype, eidto):
--- a/server/migractions.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/migractions.py Thu Nov 19 12:55:47 2009 +0100
@@ -305,35 +305,33 @@
# schema synchronization internals ########################################
- def _synchronize_permissions(self, ertype):
+ def _synchronize_permissions(self, erschema, teid):
"""permission synchronization for an entity or relation type"""
- if ertype in VIRTUAL_RTYPES:
+ if erschema in VIRTUAL_RTYPES:
return
- newrschema = self.fs_schema[ertype]
- teid = self.repo.schema[ertype].eid
- if 'update' in newrschema.ACTIONS or newrschema.final:
+ assert teid, erschema
+ if 'update' in erschema.ACTIONS or erschema.final:
# entity type
exprtype = u'ERQLExpression'
else:
# relation type
exprtype = u'RRQLExpression'
- assert teid, ertype
gm = self.group_mapping()
confirm = self.verbosity >= 2
# * remove possibly deprecated permission (eg in the persistent schema
# but not in the new schema)
# * synchronize existing expressions
# * add new groups/expressions
- for action in newrschema.ACTIONS:
+ for action in erschema.ACTIONS:
perm = '%s_permission' % action
# handle groups
- newgroups = list(newrschema.get_groups(action))
+ newgroups = list(erschema.get_groups(action))
for geid, gname in self.rqlexec('Any G, GN WHERE T %s G, G name GN, '
'T eid %%(x)s' % perm, {'x': teid}, 'x',
ask_confirm=False):
if not gname in newgroups:
if not confirm or self.confirm('remove %s permission of %s to %s?'
- % (action, ertype, gname)):
+ % (action, erschema, gname)):
self.rqlexec('DELETE T %s G WHERE G eid %%(x)s, T eid %s'
% (perm, teid),
{'x': geid}, 'x', ask_confirm=False)
@@ -341,18 +339,18 @@
newgroups.remove(gname)
for gname in newgroups:
if not confirm or self.confirm('grant %s permission of %s to %s?'
- % (action, ertype, gname)):
+ % (action, erschema, gname)):
self.rqlexec('SET T %s G WHERE G eid %%(x)s, T eid %s'
% (perm, teid),
{'x': gm[gname]}, 'x', ask_confirm=False)
# handle rql expressions
- newexprs = dict((expr.expression, expr) for expr in newrschema.get_rqlexprs(action))
+ newexprs = dict((expr.expression, expr) for expr in erschema.get_rqlexprs(action))
for expreid, expression in self.rqlexec('Any E, EX WHERE T %s E, E expression EX, '
'T eid %s' % (perm, teid),
ask_confirm=False):
if not expression in newexprs:
if not confirm or self.confirm('remove %s expression for %s permission of %s?'
- % (expression, action, ertype)):
+ % (expression, action, erschema)):
# deleting the relation will delete the expression entity
self.rqlexec('DELETE T %s E WHERE E eid %%(x)s, T eid %s'
% (perm, teid),
@@ -362,7 +360,7 @@
for expression in newexprs.values():
expr = expression.expression
if not confirm or self.confirm('add %s expression for %s permission of %s?'
- % (expr, action, ertype)):
+ % (expr, action, erschema)):
self.rqlexec('INSERT RQLExpression X: X exprtype %%(exprtype)s, '
'X expression %%(expr)s, X mainvars %%(vars)s, T %s X '
'WHERE T eid %%(x)s' % perm,
@@ -394,9 +392,7 @@
for subj, obj in rschema.iter_rdefs():
if not reporschema.has_rdef(subj, obj):
continue
- self._synchronize_rdef_schema(subj, rschema, obj)
- if syncperms:
- self._synchronize_permissions(rtype)
+ self._synchronize_rdef_schema(subj, rschema, obj, syncperms=syncperms)
def _synchronize_eschema(self, etype, syncperms=True):
"""synchronize properties of the persistent entity schema against
@@ -446,9 +442,9 @@
continue
self._synchronize_rdef_schema(subj, rschema, obj)
if syncperms:
- self._synchronize_permissions(etype)
+ self._synchronize_permissions(eschema, repoeschema.eid)
- def _synchronize_rdef_schema(self, subjtype, rtype, objtype):
+ def _synchronize_rdef_schema(self, subjtype, rtype, objtype, syncperms=True):
"""synchronize properties of the persistent relation definition schema
against its current definition:
* order and other properties
@@ -467,12 +463,14 @@
self.rqlexecall(ss.updaterdef2rql(rschema, subjtype, objtype),
ask_confirm=confirm)
# constraints
- newconstraints = list(rschema.rproperty(subjtype, objtype, 'constraints'))
+ rdef = rschema.rdef(subjtype, objtype)
+ repordef = reporschema.rdef(subjtype, objtype)
+ newconstraints = list(rdef.constraints)
# 1. remove old constraints and update constraints of the same type
# NOTE: don't use rschema.constraint_by_type because it may be
# out of sync with newconstraints when multiple
# constraints of the same type are used
- for cstr in reporschema.rproperty(subjtype, objtype, 'constraints'):
+ for cstr in repordef.constraints:
for newcstr in newconstraints:
if newcstr.type() == cstr.type():
break
@@ -496,6 +494,8 @@
self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype,
newcstr),
ask_confirm=confirm)
+ if syncperms:
+ self._synchronize_permissions(rdef, repordef.eid)
# base actions ############################################################
@@ -888,7 +888,8 @@
if isinstance(ertype, (tuple, list)):
assert len(ertype) == 3, 'not a relation definition'
assert syncprops, 'can\'t update permission for a relation definition'
- self._synchronize_rdef_schema(*ertype)
+ self._synchronize_rdef_schema(ertype[0], ertype[1], ertype[2],
+ syncperms=syncperms)
elif syncprops:
erschema = self.repo.schema[ertype]
if isinstance(erschema, CubicWebRelationSchema):
@@ -897,13 +898,14 @@
else:
self._synchronize_eschema(erschema, syncperms=syncperms)
else:
- self._synchronize_permissions(ertype)
+ erschema = self.repo.schema[ertype]
+ self._synchronize_permissions(self.fs_schema[ertype], erschema.eid)
else:
for etype in self.repo.schema.entities():
if syncprops:
self._synchronize_eschema(etype, syncperms=syncperms)
else:
- self._synchronize_permissions(etype)
+ self._synchronize_permissions(self.fs_schema[etype], erschema.eid)
if commit:
self.commit()
--- a/server/querier.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/querier.py Thu Nov 19 12:55:47 2009 +0100
@@ -71,14 +71,23 @@
# XXX has_text may have specific perm ?
if rel.r_type in READ_ONLY_RTYPES:
continue
- if not schema.rschema(rel.r_type).has_access(user, 'read'):
+ rschema = schema.rschema(rel.r_type)
+ if rschema.final:
+ eschema = schema.eschema(solution[rel.children[0].name])
+ rdef = eschema.rdef(rschema)
+ else:
+ rdef = rschema.rdef(solution[rel.children[0].name],
+ solution[rel.children[1].children[0].name])
+ if not user.matching_groups(rdef.get_groups('read')):
raise Unauthorized('read', rel.r_type)
localchecks = {}
# iterate on defined_vars and not on solutions to ignore column aliases
for varname in rqlst.defined_vars:
etype = solution[varname]
eschema = schema.eschema(etype)
- if not eschema.has_access(user, 'read'):
+ if eschema.final:
+ continue
+ if not user.matching_groups(eschema.get_groups('read')):
erqlexprs = eschema.get_rqlexprs('read')
if not erqlexprs:
ex = Unauthorized('read', etype)
--- a/server/repository.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/repository.py Thu Nov 19 12:55:47 2009 +0100
@@ -1087,7 +1087,7 @@
continue
rschema = eschema.subjrels[attr]
if rschema.final:
- if eschema.rproperty(attr, 'fulltextindexed'):
+ if getattr(eschema.rdef(attr), 'fulltextindexed', False):
need_fti_update = True
only_inline_rels = False
else:
--- a/server/schemahooks.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/schemahooks.py Thu Nov 19 12:55:47 2009 +0100
@@ -180,18 +180,6 @@
return i + 1
-class MemSchemaPermissionOperation(MemSchemaOperation):
- """base class to synchronize schema permission definitions"""
- def __init__(self, session, perm, etype_eid):
- self.perm = perm
- try:
- self.name = session.entity_from_eid(etype_eid).name
- except IndexError:
- self.error('changing permission of a no more existant type #%s',
- etype_eid)
- else:
- Operation.__init__(self, session)
-
# operations for high-level source database alteration ########################
@@ -487,7 +475,7 @@
return
subjtype, rtype, objtype = session.schema.schema_by_eid(rdef.eid)
cstrtype = self.entity.type
- oldcstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
+ oldcstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
table = SQL_PREFIX + str(subjtype)
column = SQL_PREFIX + str(rtype)
@@ -567,8 +555,7 @@
"""actually add the relation type to the instance's schema"""
eid = None # make pylint happy
def commit_event(self):
- rschema = self.schema.add_relation_type(self.kobj)
- rschema.set_default_groups()
+ self.schema.add_relation_type(self.kobj)
class MemSchemaCWRTypeUpdate(MemSchemaOperation):
@@ -606,7 +593,7 @@
def commit_event(self):
# structure should be clean, not need to remove entity's relations
# at this point
- self.rschema._rproperties[self.kobj].update(self.values)
+ self.rschema.rdef[self.kobj].update(self.values)
class MemSchemaRDefDel(MemSchemaOperation):
@@ -638,7 +625,7 @@
subjtype, rtype, objtype = self.session.schema.schema_by_eid(rdef.eid)
self.prepare_constraints(subjtype, rtype, objtype)
cstrtype = self.entity.type
- self.cstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
+ self.cstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
self.newcstr.eid = self.entity.eid
@@ -664,33 +651,33 @@
self.constraints.remove(self.cstr)
-class MemSchemaPermissionCWGroupAdd(MemSchemaPermissionOperation):
+class MemSchemaPermissionAdd(MemSchemaOperation):
"""synchronize schema when a *_permission relation has been added on a group
"""
- def __init__(self, session, perm, etype_eid, group_eid):
- self.group = session.entity_from_eid(group_eid).name
- super(MemSchemaPermissionCWGroupAdd, self).__init__(
- session, perm, etype_eid)
def commit_event(self):
"""the observed connections pool has been commited"""
try:
- erschema = self.schema[self.name]
+ erschema = self.schema.schema_by_eid(self.eid)
except KeyError:
# duh, schema not found, log error and skip operation
self.error('no schema for %s', self.name)
return
- groups = list(erschema.get_groups(self.perm))
+ perms = list(erschema.action_permissions(self.action))
+ if hasattr(self, group_eid):
+ perm = self.session.entity_from_eid(self.group_eid).name
+ else:
+ perm = erschema.rql_expression(self.expr)
try:
- groups.index(self.group)
- self.warning('group %s already have permission %s on %s',
- self.group, self.perm, erschema.type)
+ perms.index(perm)
+ self.warning('%s already in permissions for %s on %s',
+ perm, self.action, erschema)
except ValueError:
- groups.append(self.group)
- erschema.set_groups(self.perm, groups)
+ perms.append(perm)
+ erschema.set_action_permissions(self.action, perms)
-class MemSchemaPermissionCWGroupDel(MemSchemaPermissionCWGroupAdd):
+class MemSchemaPermissionDel(MemSchemaPermissionAdd):
"""synchronize schema when a *_permission relation has been deleted from a
group
"""
@@ -703,60 +690,17 @@
# duh, schema not found, log error and skip operation
self.error('no schema for %s', self.name)
return
- groups = list(erschema.get_groups(self.perm))
- try:
- groups.remove(self.group)
- erschema.set_groups(self.perm, groups)
- except ValueError:
- self.error('can\'t remove permission %s on %s to group %s',
- self.perm, erschema.type, self.group)
-
-
-class MemSchemaPermissionRQLExpressionAdd(MemSchemaPermissionOperation):
- """synchronize schema when a *_permission relation has been added on a rql
- expression
- """
- def __init__(self, session, perm, etype_eid, expression):
- self.expr = expression
- super(MemSchemaPermissionRQLExpressionAdd, self).__init__(
- session, perm, etype_eid)
-
- def commit_event(self):
- """the observed connections pool has been commited"""
+ perms = list(erschema.action_permissions(self.action))
+ if hasattr(self, group_eid):
+ perm = self.session.entity_from_eid(self.group_eid).name
+ else:
+ perm = erschema.rql_expression(self.expr)
try:
- erschema = self.schema[self.name]
- except KeyError:
- # duh, schema not found, log error and skip operation
- self.error('no schema for %s', self.name)
- return
- exprs = list(erschema.get_rqlexprs(self.perm))
- exprs.append(erschema.rql_expression(self.expr))
- erschema.set_rqlexprs(self.perm, exprs)
-
-
-class MemSchemaPermissionRQLExpressionDel(MemSchemaPermissionRQLExpressionAdd):
- """synchronize schema when a *_permission relation has been deleted from an
- rql expression
- """
-
- def commit_event(self):
- """the observed connections pool has been commited"""
- try:
- erschema = self.schema[self.name]
- except KeyError:
- # duh, schema not found, log error and skip operation
- self.error('no schema for %s', self.name)
- return
- rqlexprs = list(erschema.get_rqlexprs(self.perm))
- for i, rqlexpr in enumerate(rqlexprs):
- if rqlexpr.expression == self.expr:
- rqlexprs.pop(i)
- break
- else:
- self.error('can\'t remove permission %s on %s for expression %s',
- self.perm, erschema.type, self.expr)
- return
- erschema.set_rqlexprs(self.perm, rqlexprs)
+ perms.remove(self.group)
+ erschema.set_action_permissions(self.action, perms)
+ except ValueError:
+ self.error('can\'t remove permission %s for %s on %s',
+ perm, self.action, erschema)
class MemSchemaSpecializesAdd(MemSchemaOperation):
@@ -894,7 +838,6 @@
# but remove it before doing anything more dangerous...
schema = session.schema
eschema = schema.add_entity_type(etype)
- eschema.set_default_groups()
# generate table sql and rql to add metadata
tablesql = eschema2sql(session.pool.source('system').dbhelper, eschema,
prefix=SQL_PREFIX)
@@ -1033,8 +976,8 @@
entity = session.entity_from_eid(toeid)
subjtype, rtype, objtype = schema.schema_by_eid(fromeid)
try:
- cstr = rtype.constraint_by_type(subjtype, objtype,
- entity.cstrtype[0].name)
+ cstr = rtype.rdef(subjtype, objtype).constraint_by_type(
+ entity.cstrtype[0].name)
except IndexError:
session.critical('constraint type no more accessible')
else:
@@ -1053,13 +996,14 @@
def after_add_permission(session, subject, rtype, object):
"""added entity/relation *_permission, need to update schema"""
- perm = rtype.split('_', 1)[0]
+ action = rtype.split('_', 1)[0]
if session.describe(object)[0] == 'CWGroup':
- MemSchemaPermissionCWGroupAdd(session, perm, subject, object)
+ MemSchemaPermissionAdd(session, action=action, eid=subject,
+ group_eid=object)
else: # RQLExpression
- expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR',
- {'x': object}, 'x')[0][0]
- MemSchemaPermissionRQLExpressionAdd(session, perm, subject, expr)
+ expr = session.entity_from_eid(object).expression
+ MemSchemaPermissionAdd(session, action=action, eid=subject,
+ expr=expr)
def before_del_permission(session, subject, rtype, object):
@@ -1069,13 +1013,12 @@
"""
if subject in session.transaction_data.get('pendingeids', ()):
return
- perm = rtype.split('_', 1)[0]
+ action = rtype.split('_', 1)[0]
if session.describe(object)[0] == 'CWGroup':
- MemSchemaPermissionCWGroupDel(session, perm, subject, object)
+ MemSchemaPermissionDel(session, action=action, eid=subject, group_eid=object)
else: # RQLExpression
- expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR',
- {'x': object}, 'x')[0][0]
- MemSchemaPermissionRQLExpressionDel(session, perm, subject, expr)
+ expr = session.entity_from_eid(object).expression
+ MemSchemaPermissionDel(session, action=action, eid=subject, expr=expr)
def after_add_specializes(session, subject, rtype, object):
--- a/server/schemaserial.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/schemaserial.py Thu Nov 19 12:55:47 2009 +0100
@@ -256,7 +256,7 @@
actperms.append(erschema.rql_expression(*something))
else: # group name
actperms.append(something)
- erschema.set_permissions(action, actperms)
+ erschema.set_action_permissions(action, actperms)
def deserialize_rdef_constraints(session):
@@ -513,25 +513,51 @@
yield erperms2rql(schema[rtype], groupmapping)
def erperms2rql(erschema, groupmapping):
+ if hasattr(erschema, 'iter_rdefs'):
+ # relation schema
+ if erschema.final:
+ etype = 'CWAttribute'
+ else:
+ etype = 'CWRelation'
+ for subject, object in erschema.iter_rdefs():
+ permissions = erschema.rproperty(subject, object, 'permissions')
+ for rql, args in _erperms2rql(erschema.rproperties(subject, object),
+ groupmapping):
+ args['st'] = str(subject)
+ args['rt'] = str(erschema)
+ args['ot'] = str(object)
+ yield rql + 'X is %s, X from_entity ST, X to_entity OT, '\
+ 'X relation_type RT, RT name %%(rt)s, ST name %%(st)s, '\
+ 'OT name %%(ot)s' % etype, args
+ else:
+ # entity schema
+ for rql, args in _erperms2rql(erschema, groupmapping):
+ args['name'] = str(eschema)
+ yield rql + 'X is CWEType, X name %(name)s', args
+
+def _erperms2rql(erschema, groupmapping):
"""return rql insert statements to enter the entity or relation
schema's permissions in the database as
[read|add|delete|update]_permission relations between CWEType/CWRType
and CWGroup entities
"""
- etype = isinstance(erschema, schemamod.EntitySchema) and 'CWEType' or 'CWRType'
for action in erschema.ACTIONS:
- for group in sorted(erschema.get_groups(action)):
- try:
- yield ('SET X %s_permission Y WHERE X is %s, X name %%(name)s, Y eid %s'
- % (action, etype, groupmapping[group]), {'name': str(erschema)})
- except KeyError:
- continue
- for rqlexpr in sorted(erschema.get_rqlexprs(action)):
- yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, '
- 'E mainvars %%(v)s, X %s_permission E '
- 'WHERE X is %s, X name "%s"' % (action, etype, erschema),
- {'e': unicode(rqlexpr.expression), 'v': unicode(rqlexpr.mainvars),
- 't': unicode(rqlexpr.__class__.__name__)})
+ for group_or_rqlexpr in erschema.action_permissions(action):
+ if isinstance(group_or_rqlexpr, basestring):
+ # group
+ try:
+ yield ('SET X %s_permission Y WHERE Y eid %%(g)s' % action,
+ {'g': groupmapping[group_or_rqlexpr]})
+ except KeyError:
+ continue
+ else:
+ # rqlexpr
+ rqlexpr = group_or_rqlexpr
+ yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, '
+ 'E mainvars %%(v)s, X %s_permission E WHERE ' % action,
+ {'e': unicode(rqlexpr.expression),
+ 'v': unicode(rqlexpr.mainvars),
+ 't': unicode(rqlexpr.__class__.__name__)})
def updateeschema2rql(eschema):
--- a/server/securityhooks.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/securityhooks.py Thu Nov 19 12:55:47 2009 +0100
@@ -25,10 +25,10 @@
for attr in editedattrs:
if attr in defaults:
continue
- rschema = eschema.subjrels[attr]
- if rschema.final: # non final relation are checked by other hooks
+ rdef = eschema.rdef(attr)
+ if rdef.final: # non final relation are checked by other hooks
# add/delete should be equivalent (XXX: unify them into 'update' ?)
- rschema.check_perm(session, 'add', eid)
+ rdef.check_perm(session, 'add', eid=eid)
class CheckEntityPermissionOp(LateOperation):
@@ -43,7 +43,10 @@
class CheckRelationPermissionOp(LateOperation):
def precommit_event(self):
- self.rschema.check_perm(self.session, self.action, self.fromeid, self.toeid)
+ rdef = self.rschema.rdef(self.session.describe(self.fromeid)[0],
+ self.session.describe(self.toeid)[0])
+ rdef.check_perm(self.session, self.action,
+ fromeid=self.fromeid, toeid=self.toeid)
def commit_event(self):
pass
@@ -65,7 +68,7 @@
def before_del_entity(session, eid):
if not session.is_super_session:
eschema = session.repo.schema[session.describe(eid)[0]]
- eschema.check_perm(session, 'delete', eid)
+ eschema.check_perm(session, 'delete', eid=eid)
def before_add_relation(session, fromeid, rtype, toeid):
@@ -74,26 +77,33 @@
if (fromeid, rtype, toeid) in nocheck:
return
rschema = session.repo.schema[rtype]
- rschema.check_perm(session, 'add', fromeid, toeid)
+ rdef = rschema.rdef(session.describe(fromeid)[0],
+ session.describe(toeid)[0])
+ rdef.check_perm(session, 'add', fromeid=fromeid, toeid=toeid)
def after_add_relation(session, fromeid, rtype, toeid):
if not rtype in BEFORE_ADD_RELATIONS and not session.is_super_session:
nocheck = session.transaction_data.get('skip-security', ())
if (fromeid, rtype, toeid) in nocheck:
return
- rschema = session.repo.schema[rtype]
+ rschema = session.repo.schema.rschema(rtype)
if rtype in ON_COMMIT_ADD_RELATIONS:
CheckRelationPermissionOp(session, action='add', rschema=rschema,
fromeid=fromeid, toeid=toeid)
else:
- rschema.check_perm(session, 'add', fromeid, toeid)
+ rdef = rschema.rdef(session.describe(fromeid)[0],
+ session.describe(toeid)[0])
+ rdef.check_perm(session, 'add', fromeid=fromeid, toeid=toeid)
def before_del_relation(session, fromeid, rtype, toeid):
if not session.is_super_session:
nocheck = session.transaction_data.get('skip-security', ())
if (fromeid, rtype, toeid) in nocheck:
return
- session.repo.schema[rtype].check_perm(session, 'delete', fromeid, toeid)
+ rschema = session.vreg.schema.rschema(rtype)
+ rdef = rschema.rdef(session.describe(fromeid)[0],
+ session.describe(toeid)[0])
+ rdef.check_perm(session, 'delete', fromeid=fromeid, toeid=toeid)
def register_security_hooks(hm):
"""register meta-data related hooks on the hooks manager"""
--- a/server/test/data/migratedapp/schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/test/data/migratedapp/schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -13,7 +13,7 @@
ERQLExpression, RRQLExpression)
class Affaire(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
'update': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')),
@@ -27,7 +27,7 @@
concerne = SubjectRelation('Societe')
class concerne(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', RRQLExpression('U has_update_permission S')),
'delete': ('managers', RRQLExpression('O owned_by U')),
@@ -42,7 +42,7 @@
class Note(Para):
__specializes_schema__ = True
- permissions = {'read': ('managers', 'users', 'guests',),
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
'update': ('managers', 'owners',),
'delete': ('managers', ),
'add': ('managers',
@@ -63,7 +63,7 @@
summary = String(maxsize=512)
class ecrit_par(RelationType):
- permissions = {'read': ('managers', 'users', 'guests',),
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
'delete': ('managers', ),
'add': ('managers',
RRQLExpression('O require_permission P, P name "add_note", '
@@ -105,7 +105,7 @@
connait = SubjectRelation('Personne', symetric=True)
class Societe(WorkflowableEntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'update': ('managers', 'owners'),
'delete': ('managers', 'owners'),
--- a/server/test/data/schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/test/data/schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -13,7 +13,7 @@
ERQLExpression, RRQLExpression)
class Affaire(WorkflowableEntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',
ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
@@ -39,7 +39,7 @@
class Societe(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
@@ -121,28 +121,28 @@
symetric = True
class concerne(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', RRQLExpression('U has_update_permission S')),
'delete': ('managers', RRQLExpression('O owned_by U')),
}
class travaille(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', RRQLExpression('U has_update_permission S')),
'delete': ('managers', RRQLExpression('O owned_by U')),
}
class para(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'add': ('managers', ERQLExpression('X in_state S, S name "todo"')),
'delete': ('managers', ERQLExpression('X in_state S, S name "todo"')),
}
class test(RelationType):
- permissions = {'read': ('managers', 'users', 'guests'),
+ __permissions__ = {'read': ('managers', 'users', 'guests'),
'delete': ('managers',),
'add': ('managers',)}
--- a/server/test/unittest_security.py Wed Nov 18 09:16:38 2009 +0100
+++ b/server/test/unittest_security.py Thu Nov 19 12:55:47 2009 +0100
@@ -14,13 +14,13 @@
def setUp(self):
RepositoryBasedTC.setUp(self)
self.create_user('iaminusersgrouponly')
- self.readoriggroups = self.schema['Personne'].get_groups('read')
- self.addoriggroups = self.schema['Personne'].get_groups('add')
+ self.readoriggroups = self.schema['Personne'].permissions['read']
+ self.addoriggroups = self.schema['Personne'].permissions['add']
def tearDown(self):
RepositoryBasedTC.tearDown(self)
- self.schema['Personne'].set_groups('read', self.readoriggroups)
- self.schema['Personne'].set_groups('add', self.addoriggroups)
+ self.schema['Personne'].set_action_permissions('read', self.readoriggroups)
+ self.schema['Personne'].set_action_permissions('add', self.addoriggroups)
class LowLevelSecurityFunctionTC(BaseSecurityTC):
@@ -29,7 +29,7 @@
rql = u'Personne U where U nom "managers"'
rqlst = self.repo.vreg.rqlhelper.parse(rql).children[0]
origgroups = self.schema['Personne'].get_groups('read')
- self.schema['Personne'].set_groups('read', ('users', 'managers'))
+ self.schema['Personne'].set_action_permissions('read', ('users', 'managers'))
self.repo.vreg.rqlhelper.compute_solutions(rqlst)
solution = rqlst.solutions[0]
check_read_access(self.schema, self.session.user, rqlst, solution)
@@ -96,8 +96,8 @@
def test_update_security_2(self):
cnx = self.login('anon')
cu = cnx.cursor()
- self.repo.schema['Personne'].set_groups('read', ('users', 'managers'))
- self.repo.schema['Personne'].set_groups('add', ('guests', 'users', 'managers'))
+ self.repo.schema['Personne'].set_action_permissions('read', ('users', 'managers'))
+ self.repo.schema['Personne'].set_action_permissions('add', ('guests', 'users', 'managers'))
self.assertRaises(Unauthorized, cu.execute, "SET X nom 'bidulechouette' WHERE X is Personne")
#self.assertRaises(Unauthorized, cnx.commit)
# test nothing has actually been inserted
@@ -177,7 +177,7 @@
ent = rset.get_entity(0, 0)
session.set_pool() # necessary
self.assertRaises(Unauthorized,
- ent.e_schema.check_perm, session, 'update', ent.eid)
+ ent.e_schema.check_perm, session, 'update', eid=ent.eid)
self.assertRaises(Unauthorized,
cu.execute, "SET P travaille S WHERE P is Personne, S is Societe")
# test nothing has actually been inserted:
@@ -230,7 +230,7 @@
# read security test
def test_read_base(self):
- self.schema['Personne'].set_groups('read', ('users', 'managers'))
+ self.schema['Personne'].set_action_permissions('read', ('users', 'managers'))
cnx = self.login('anon')
cu = cnx.cursor()
self.assertRaises(Unauthorized,
@@ -281,7 +281,7 @@
self.execute("INSERT Personne X: X nom 'bidule'")
self.execute("INSERT Societe X: X nom 'bidule'")
self.commit()
- self.schema['Personne'].set_groups('read', ('managers',))
+ self.schema['Personne'].set_action_permissions('read', ('managers',))
cnx = self.login('iaminusersgrouponly')
cu = cnx.cursor()
rset = cu.execute('Any N WHERE N has_text "bidule"')
@@ -293,7 +293,7 @@
self.execute("INSERT Personne X: X nom 'bidule'")
self.execute("INSERT Societe X: X nom 'bidule'")
self.commit()
- self.schema['Personne'].set_groups('read', ('managers',))
+ self.schema['Personne'].set_action_permissions('read', ('managers',))
cnx = self.login('anon')
cu = cnx.cursor()
rset = cu.execute('Any N,U WHERE N has_text "bidule", N owned_by U?')
@@ -371,8 +371,8 @@
def test_attribute_read_security(self):
# anon not allowed to see users'login, but they can see users
- self.repo.schema['CWUser'].set_groups('read', ('guests', 'users', 'managers'))
- self.repo.schema['login'].set_groups('read', ('users', 'managers'))
+ self.repo.schema['CWUser'].set_action_permissions('read', ('guests', 'users', 'managers'))
+ self.repo.schema['CWUser'].rdef('login').set_action_permissions('read', ('users', 'managers'))
cnx = self.login('anon')
cu = cnx.cursor()
rset = cu.execute('CWUser X')
@@ -494,11 +494,11 @@
# needed to avoid check_perm error
session.set_pool()
# needed to remove rql expr granting update perm to the user
- self.schema['Affaire'].set_rqlexprs('update', ())
+ self.schema['Affaire'].set_action_permissions('update', self.schema['Affaire'].get_groups('update'))
self.assertRaises(Unauthorized,
- self.schema['Affaire'].check_perm, session, 'update', eid)
+ self.schema['Affaire'].check_perm, session, 'update', eid=eid)
cu = cnx.cursor()
- self.schema['Affaire'].set_groups('read', ('users',))
+ self.schema['Affaire'].set_action_permissions('read', ('users',))
try:
aff = cu.execute('Any X WHERE X ref "ARCT01"').get_entity(0, 0)
aff.fire_transition('abort')
@@ -510,7 +510,7 @@
# from the current state but Unauthorized if it exists but user can't pass it
self.assertRaises(ValidationError, user.fire_transition, 'deactivate')
finally:
- self.schema['Affaire'].set_groups('read', ('managers',))
+ self.schema['Affaire'].set_action_permissions('read', ('managers',))
def test_trinfo_security(self):
aff = self.execute('INSERT Affaire X: X ref "ARCT01"').get_entity(0, 0)
--- a/sobjects/notification.py Wed Nov 18 09:16:38 2009 +0100
+++ b/sobjects/notification.py Thu Nov 19 12:55:47 2009 +0100
@@ -269,14 +269,16 @@
changes = self.req.transaction_data['changes'][self.rset[0][0]]
_ = self.req._
formatted_changes = []
+ entity = self.entity(self.row or 0, self.col or 0)
for attr, oldvalue, newvalue in sorted(changes):
# check current user has permission to see the attribute
rschema = self.vreg.schema[attr]
if rschema.final:
- if not rschema.has_perm(self.req, 'read', eid=self.rset[0][0]):
+ rdef = entity.e_schema.rdef(rschema)
+ if not rdef.has_perm(self.req, 'read', eid=self.rset[0][0]):
continue
# XXX suppose it's a subject relation...
- elif not rschema.has_perm(self.req, 'read', fromeid=self.rset[0][0]):
+ elif not rschema.has_perm(self.req, 'read', fromeid=self.rset[0][0]): # XXX toeid
continue
if attr in self.no_detailed_change_attrs:
msg = _('%s updated') % _(attr)
--- a/test/data/erqlexpr_on_ertype.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/data/erqlexpr_on_ertype.py Thu Nov 19 12:55:47 2009 +0100
@@ -9,7 +9,7 @@
from cubicweb.schema import ERQLExpression
class ToTo(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',),
'add': ('managers',),
'update': ('managers',),
@@ -18,7 +18,7 @@
toto = SubjectRelation('TuTu')
class TuTu(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',),
'add': ('managers',),
'update': ('managers',),
@@ -26,7 +26,7 @@
}
class toto(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', ),
'add': ('managers', ERQLExpression('S bla Y'),),
'delete': ('managers',),
--- a/test/data/rewrite/schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/data/rewrite/schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -2,7 +2,7 @@
from cubicweb.schema import ERQLExpression
class Affaire(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',
ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
@@ -15,7 +15,7 @@
class Societe(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers', 'users', 'guests'),
'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
--- a/test/data/rqlexpr_on_ertype_read.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/data/rqlexpr_on_ertype_read.py Thu Nov 19 12:55:47 2009 +0100
@@ -9,7 +9,7 @@
from cubicweb.schema import RRQLExpression
class ToTo(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',),
'add': ('managers',),
'update': ('managers',),
@@ -18,7 +18,7 @@
toto = SubjectRelation('TuTu')
class TuTu(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',),
'add': ('managers',),
'update': ('managers',),
@@ -26,7 +26,7 @@
}
class toto(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', RRQLExpression('S bla Y'), ),
'add': ('managers',),
'delete': ('managers',),
--- a/test/data/rrqlexpr_on_attr.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/data/rrqlexpr_on_attr.py Thu Nov 19 12:55:47 2009 +0100
@@ -9,7 +9,7 @@
from cubicweb.schema import RRQLExpression
class ToTo(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers',),
'add': ('managers',),
'update': ('managers',),
@@ -18,7 +18,7 @@
attr = String()
class attr(RelationType):
- permissions = {
+ __permissions__ = {
'read': ('managers', ),
'add': ('managers', RRQLExpression('S bla Y'),),
'delete': ('managers',),
--- a/test/data/rrqlexpr_on_eetype.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/data/rrqlexpr_on_eetype.py Thu Nov 19 12:55:47 2009 +0100
@@ -9,7 +9,7 @@
from cubicweb.schema import RRQLExpression
class ToTo(EntityType):
- permissions = {
+ __permissions__ = {
'read': ('managers', RRQLExpression('S bla Y'),),
'add': ('managers',),
'update': ('managers',),
--- a/test/unittest_entity.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/unittest_entity.py Thu Nov 19 12:55:47 2009 +0100
@@ -63,7 +63,7 @@
def test_copy_with_nonmeta_composite_inlined(self):
p = self.add_entity('Personne', nom=u'toto')
oe = self.add_entity('Note', type=u'x')
- self.schema['ecrit_par'].set_rproperty('Note', 'Personne', 'composite', 'subject')
+ self.schema['ecrit_par'].rdef('Note', 'Personne').composite = 'subject'
self.execute('SET T ecrit_par U WHERE T eid %(t)s, U eid %(u)s',
{'t': oe.eid, 'u': p.eid}, ('t','u'))
e = self.add_entity('Note', type=u'z')
@@ -127,10 +127,10 @@
Note = self.vreg['etypes'].etype_class('Note')
peschema = Personne.e_schema
seschema = Societe.e_schema
- peschema.subjrels['travaille'].set_rproperty(peschema, seschema, 'cardinality', '1*')
- peschema.subjrels['connait'].set_rproperty(peschema, peschema, 'cardinality', '11')
- peschema.subjrels['evaluee'].set_rproperty(peschema, Note.e_schema, 'cardinality', '1*')
- seschema.subjrels['evaluee'].set_rproperty(seschema, Note.e_schema, 'cardinality', '1*')
+ peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '1*'
+ peschema.subjrels['connait'].rdef(peschema, peschema).cardinality = '11'
+ peschema.subjrels['evaluee'].rdef(peschema, Note.e_schema).cardinality = '1*'
+ seschema.subjrels['evaluee'].rdef(seschema, Note.e_schema).cardinality = '1*'
# testing basic fetch_attrs attribute
self.assertEquals(Personne.fetch_rql(user),
'Any X,AA,AB,AC ORDERBY AA ASC '
@@ -165,13 +165,13 @@
self.assertEquals(Personne.fetch_rql(user), 'Any X,AA,AB ORDERBY AA ASC '
'WHERE X is Personne, X nom AA, X connait AB?')
# testing optional relation
- peschema.subjrels['travaille'].set_rproperty(peschema, seschema, 'cardinality', '?*')
+ peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '?*'
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
Societe.fetch_attrs = ('nom',)
self.assertEquals(Personne.fetch_rql(user),
'Any X,AA,AB,AC,AD ORDERBY AA ASC WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
# testing relation with cardinality > 1
- peschema.subjrels['travaille'].set_rproperty(peschema, seschema, 'cardinality', '**')
+ peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '**'
self.assertEquals(Personne.fetch_rql(user),
'Any X,AA,AB ORDERBY AA ASC WHERE X is Personne, X nom AA, X prenom AB')
# XXX test unauthorized attribute
--- a/test/unittest_rqlrewrite.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/unittest_rqlrewrite.py Thu Nov 19 12:55:47 2009 +0100
@@ -18,7 +18,8 @@
config = TestServerConfiguration('data/rewrite')
config.bootstrap_cubes()
schema = config.load_schema()
-schema.add_relation_def(mock_object(subject='Card', name='in_state', object='State', cardinality='1*'))
+from yams.buildobjs import RelationDefinition
+schema.add_relation_def(RelationDefinition(subject='Card', name='in_state', object='State', cardinality='1*'))
rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid',
'has_text': 'fti'})
--- a/test/unittest_schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/test/unittest_schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -19,7 +19,7 @@
from yams.reader import PyFileReader
from cubicweb.schema import CubicWebSchema, CubicWebEntitySchema, \
- RQLConstraint, CubicWebSchemaLoader, ERQLExpression, RRQLExpression, \
+ RQLConstraint, CubicWebSchemaLoader, RQLExpression, ERQLExpression, RRQLExpression, \
normalize_expression, order_eschemas
from cubicweb.devtools import TestServerConfiguration as TestConfiguration
@@ -44,7 +44,7 @@
schema = CubicWebSchema('Test Schema')
enote = schema.add_entity_type(EntityType('Note'))
eaffaire = schema.add_entity_type(EntityType('Affaire'))
-eperson = schema.add_entity_type(EntityType('Personne', permissions=PERSONNE_PERMISSIONS))
+eperson = schema.add_entity_type(EntityType('Personne', __permissions__=PERSONNE_PERMISSIONS))
esociete = schema.add_entity_type(EntityType('Societe'))
RELS = (
@@ -73,12 +73,13 @@
for rel in RELS:
_from, _type, _to = rel.split()
if not _type.lower() in done:
- if _type == 'concerne':
- schema.add_relation_type(RelationType(_type, permissions=CONCERNE_PERMISSIONS))
- else:
- schema.add_relation_type(RelationType(_type))
+ schema.add_relation_type(RelationType(_type))
done[_type.lower()] = True
- schema.add_relation_def(RelationDefinition(_from, _type, _to))
+ if _type == 'concerne':
+ schema.add_relation_def(RelationDefinition(_from, _type, _to,
+ __permissions__=CONCERNE_PERMISSIONS))
+ else:
+ schema.add_relation_def(RelationDefinition(_from, _type, _to))
class CubicWebSchemaTC(TestCase):
@@ -94,26 +95,24 @@
self.assertEqual(schema.rschema('concerne').type, 'concerne')
def test_entity_perms(self):
- eperson.set_default_groups()
self.assertEqual(eperson.get_groups('read'), set(('managers', 'users', 'guests')))
self.assertEqual(eperson.get_groups('update'), set(('managers', 'owners',)))
self.assertEqual(eperson.get_groups('delete'), set(('managers', 'owners')))
self.assertEqual(eperson.get_groups('add'), set(('managers',)))
self.assertEqual([str(e) for e in eperson.get_rqlexprs('add')],
['Any X WHERE X travaille S, S owned_by U, X eid %(x)s, U eid %(u)s'])
- eperson.set_groups('read', ('managers',))
+ eperson.set_action_permissions('read', ('managers',))
self.assertEqual(eperson.get_groups('read'), set(('managers',)))
def test_relation_perms(self):
- rconcerne = schema.rschema('concerne')
- rconcerne.set_default_groups()
+ rconcerne = schema.rschema('concerne').rdef('Personne', 'Societe')
self.assertEqual(rconcerne.get_groups('read'), set(('managers', 'users', 'guests')))
self.assertEqual(rconcerne.get_groups('delete'), set(('managers',)))
self.assertEqual(rconcerne.get_groups('add'), set(('managers', )))
- rconcerne.set_groups('read', ('managers',))
+ rconcerne.set_action_permissions('read', ('managers',))
self.assertEqual(rconcerne.get_groups('read'), set(('managers',)))
self.assertEqual([str(e) for e in rconcerne.get_rqlexprs('add')],
- ['Any S WHERE U has_update_permission S, S eid %(s)s, U eid %(u)s'])
+ ['Any S,U WHERE U has_update_permission S, S eid %(s)s, U eid %(u)s'])
def test_erqlexpression(self):
self.assertRaises(RQLSyntaxError, ERQLExpression, '1')
@@ -124,7 +123,7 @@
self.assertRaises(Exception, RRQLExpression, '1')
self.assertRaises(RQLSyntaxError, RRQLExpression, 'O X Y')
expr = RRQLExpression('U has_update_permission O')
- self.assertEquals(str(expr), 'Any O WHERE U has_update_permission O, O eid %(o)s, U eid %(u)s')
+ self.assertEquals(str(expr), 'Any O,U WHERE U has_update_permission O, O eid %(o)s, U eid %(u)s')
loader = CubicWebSchemaLoader()
config = TestConfiguration('data')
@@ -215,9 +214,9 @@
self.assertListEquals(rels, ['bookmarked_by', 'created_by', 'for_user',
'identity', 'owned_by', 'wf_info_for'])
rschema = schema.rschema('relation_type')
- properties = rschema.rproperties('CWAttribute', 'CWRType')
- self.assertEquals(properties['cardinality'], '1*')
- constraints = properties['constraints']
+ properties = rschema.rdef('CWAttribute', 'CWRType')
+ self.assertEquals(properties.cardinality, '1*')
+ constraints = properties.constraints
self.failUnlessEqual(len(constraints), 1, constraints)
constraint = constraints[0]
self.failUnless(isinstance(constraint, RQLConstraint))
@@ -246,13 +245,13 @@
self._test('rrqlexpr_on_eetype.py', "can't use RRQLExpression on an entity type, use an ERQLExpression (ToTo)")
def test_erqlexpr_on_rtype(self):
- self._test('erqlexpr_on_ertype.py', "can't use ERQLExpression on a relation type, use a RRQLExpression (toto)")
+ self._test('erqlexpr_on_ertype.py', "can't use ERQLExpression on relation ToTo toto TuTu, use a RRQLExpression")
def test_rqlexpr_on_rtype_read(self):
- self._test('rqlexpr_on_ertype_read.py', "can't use rql expression for read permission of a relation type (toto)")
+ self._test('rqlexpr_on_ertype_read.py', "can't use rql expression for read permission of relation ToTo toto TuTu")
def test_rrqlexpr_on_attr(self):
- self._test('rrqlexpr_on_attr.py', "can't use RRQLExpression on a final relation type (eg attribute relation), use an ERQLExpression (attr)")
+ self._test('rrqlexpr_on_attr.py', "can't use RRQLExpression on attribute ToTo.attr[String], use an ERQLExpression")
class NormalizeExpressionTC(TestCase):
@@ -261,5 +260,9 @@
self.assertEquals(normalize_expression('X bla Y,Y blur Z , Z zigoulou X '),
'X bla Y, Y blur Z, Z zigoulou X')
+class RQLExpressionTC(TestCase):
+ def test_comparison(self):
+ self.assertEquals(ERQLExpression('X is CWUser', 'X', 0), ERQLExpression('X is CWUser', 'X', 0))
+ self.assertNotEquals(ERQLExpression('X is CWUser', 'X', 0), ERQLExpression('X is CWGroup', 'X', 0))
if __name__ == '__main__':
unittest_main()
--- a/web/uicfg.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/uicfg.py Thu Nov 19 12:55:47 2009 +0100
@@ -73,30 +73,24 @@
from cubicweb.web import formwidgets
-def card_from_role(card, role):
- if role == 'subject':
- return card[0]
- assert role in ('object', 'sobject'), repr(role)
- return card[1]
-
# primary view configuration ##################################################
def init_primaryview_section(rtag, sschema, rschema, oschema, role):
if rtag.get(sschema, rschema, oschema, role) is None:
- card = card_from_role(rschema.rproperty(sschema, oschema, 'cardinality'), role)
- composed = rschema.rproperty(sschema, oschema, 'composite') == neg_role(role)
+ rdef = rschema.rdef(sschema, oschema)
if rschema.final:
if rschema.meta or sschema.is_metadata(rschema) \
or oschema.type in ('Password', 'Bytes'):
section = 'hidden'
else:
section = 'attributes'
- elif card in '1+':
- section = 'attributes'
- elif composed:
- section = 'relations'
else:
- section = 'sideboxes'
+ if rdef.role_cardinality(role) in '1+':
+ section = 'attributes'
+ elif rdef.composite == neg_role(role):
+ section = 'relations'
+ else:
+ section = 'sideboxes'
rtag.tag_relation((sschema, rschema, oschema, role), section)
primaryview_section = RelationTags('primaryview_section',
@@ -177,13 +171,8 @@
elif sschema.is_metadata(rschema):
section = 'metadata'
else:
- if role == 'subject':
- card = rschema.rproperty(sschema, oschema, 'cardinality')[0]
- composed = rschema.rproperty(sschema, oschema, 'composite') == 'object'
- else:
- card = rschema.rproperty(sschema, oschema, 'cardinality')[1]
- composed = rschema.rproperty(sschema, oschema, 'composite') == 'subject'
- if card in '1+':
+ rdef = rschema.rdef(sschema, oschema)
+ if rdef.role_cardinality(role) in '1+':
section = 'primary'
elif rschema.final:
section = 'secondary'
@@ -217,9 +206,8 @@
# 'link' / 'create' relation tags, used to control the "add entity" submenu
def init_actionbox_appearsin_addmenu(rtag, sschema, rschema, oschema, role):
if rtag.get(sschema, rschema, oschema, role) is None:
- card = rschema.rproperty(sschema, oschema, 'cardinality')[role == 'object']
- if not card in '?1' and \
- rschema.rproperty(sschema, oschema, 'composite') == role:
+ rdef = rschema.rdef(sschema, oschema)
+ if not rdef.role_cardinality(role) in '?1' and rdef.composite == role:
rtag.tag_relation((sschema, rschema, oschema, role), True)
actionbox_appearsin_addmenu = RelationTagsBool('actionbox_appearsin_addmenu',
--- a/web/views/actions.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/views/actions.py Thu Nov 19 12:55:47 2009 +0100
@@ -268,20 +268,21 @@
for rschema in rschemas:
if rschema.final:
continue
- # check the relation can be added as well
- # XXX consider autoform_permissions_overrides?
- if role == 'subject'and not rschema.has_perm(req, 'add',
- fromeid=entity.eid):
- continue
- if role == 'object'and not rschema.has_perm(req, 'add',
- toeid=entity.eid):
- continue
- # check the target types can be added as well
for teschema in rschema.targets(eschema, role):
if not appearsin_addmenu.etype_get(eschema, rschema,
role, teschema):
continue
- if teschema.has_local_role('add') or teschema.has_perm(req, 'add'):
+ rdef = rschema.role_rdef(eschema, teschema, role)
+ # check the relation can be added
+ # XXX consider autoform_permissions_overrides?
+ if role == 'subject'and not rdef.has_perm(
+ req, 'add', fromeid=entity.eid):
+ continue
+ if role == 'object'and not rdef.has_perm(
+ req, 'add', toeid=entity.eid):
+ continue
+ # check the target types can be added as well
+ if teschema.may_have_permission('add', req):
yield rschema, teschema, role
def linkto_url(self, entity, rtype, etype, target):
--- a/web/views/autoform.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/views/autoform.py Thu Nov 19 12:55:47 2009 +0100
@@ -75,10 +75,18 @@
# check category first, potentially lower cost than checking
# permission which may imply rql queries
if categories is not None:
- targetschemas = [tschema for tschema in targetschemas
- if rtags.etype_get(eschema, rschema, role, tschema) in categories]
- if not targetschemas:
+ _targetschemas = []
+ for tschema in targetschemas:
+ if not rtags.etype_get(eschema, rschema, role, tschema) in categories:
+ continue
+ rdef = rschema.role_rdef(eschema, tschema, role)
+ if not ((not strict and rdef.has_local_role(permission)) or
+ rdef.has_perm(entity.req, permission, fromeid=eid)):
+ continue
+ _targetschemas.append(tschema)
+ if not _targetschemas:
continue
+ targetschemas = _targetschemas
if permission is not None:
# tag allowing to hijack the permission machinery when
# permission is not verifiable until the entity is actually
@@ -87,28 +95,22 @@
yield (rschema, targetschemas, role)
continue
if rschema.final:
- if not rschema.has_perm(entity.req, permission, eid):
+ if not eschema.rdef(rschema).has_perm(entity.req, permission, eid=eid):
continue
elif role == 'subject':
- if not ((not strict and rschema.has_local_role(permission)) or
- rschema.has_perm(entity.req, permission, fromeid=eid)):
- continue
# on relation with cardinality 1 or ?, we need delete perm as well
# if the relation is already set
if (permission == 'add'
- and rschema.cardinality(eschema, targetschemas[0], role) in '1?'
+ and rschema.rdef(eschema, targetschemas[0]).role_cardinality(role) in '1?'
and eid and entity.related(rschema.type, role)
and not rschema.has_perm(entity.req, 'delete', fromeid=eid,
toeid=entity.related(rschema.type, role)[0][0])):
continue
elif role == 'object':
- if not ((not strict and rschema.has_local_role(permission)) or
- rschema.has_perm(entity.req, permission, toeid=eid)):
- continue
# on relation with cardinality 1 or ?, we need delete perm as well
# if the relation is already set
if (permission == 'add'
- and rschema.cardinality(targetschemas[0], eschema, role) in '1?'
+ and rschema.rdef(targetschemas[0], eschema).role_cardinality(role) in '1?'
and eid and entity.related(rschema.type, role)
and not rschema.has_perm(entity.req, 'delete', toeid=eid,
fromeid=entity.related(rschema.type, role)[0][0])):
--- a/web/views/owl.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/views/owl.py Thu Nov 19 12:55:47 2009 +0100
@@ -71,10 +71,8 @@
if writeprefix:
self.w(OWL_CLOSING_ROOT)
- def should_display_rschema(self, rschema):
- return not rschema in self.skiptypes and (
- rschema.has_local_role('read') or
- rschema.has_perm(self.req, 'read'))
+ def should_display_rschema(self, eschema, rschema, tschemas, role):
+ return rschema.may_have_permissions('read', self.req, eschema, role)
def visit_schema(self, skiptypes):
"""get a layout for a whole schema"""
@@ -94,7 +92,7 @@
self.w(u'<owl:Class rdf:ID="%s">'% eschema)
self.w(u'<!-- relations -->')
for rschema, targetschemas, role in eschema.relation_definitions():
- if not self.should_display_rschema(rschema):
+ if not self.should_display_rschema(eschema, rschema, targetschemas, role):
continue
for oeschema in targetschemas:
if role == 'subject':
@@ -112,7 +110,7 @@
self.w(u'<!-- attributes -->')
for rschema, aschema in eschema.attribute_definitions():
- if not self.should_display_rschema(rschema):
+ if not self.should_display_rschema(eschema, rschema, (aschema,), 'subject'):
continue
self.w(u'''<rdfs:subClassOf>
<owl:Restriction>
@@ -125,7 +123,7 @@
def visit_property_schema(self, eschema):
"""get a layout for property entity OWL schema"""
for rschema, targetschemas, role in eschema.relation_definitions():
- if not self.should_display_rschema(rschema):
+ if not self.should_display_rschema(eschema, rschema, targetschemas, role):
continue
for oeschema in targetschemas:
self.w(u'''<owl:ObjectProperty rdf:ID="%s">
@@ -135,7 +133,7 @@
def visit_property_object_schema(self, eschema):
for rschema, aschema in eschema.attribute_definitions():
- if not self.should_display_rschema(rschema):
+ if not self.should_display_rschema(eschema, rschema, (aschema,), 'subject'):
continue
self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
<rdfs:domain rdf:resource="#%s"/>
@@ -174,7 +172,8 @@
for rschema, aschema in eschema.attribute_definitions():
if rschema.meta:
continue
- if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+ rdef = rschema.rdef(eschema, aschema)
+ if not rdef.may_have_permission('read', self.req):
continue
aname = rschema.type
if aname == 'eid':
@@ -189,8 +188,10 @@
for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.meta:
continue
- if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
- continue
+ for tschema in targetschemas:
+ rdef = rschema.role_rdef(eschema, tschema, role)
+ if not rdef.may_have_permission('read', self.req):
+ continue
if role == 'object':
attr = 'reverse_%s' % rschema.type
else:
--- a/web/views/schema.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/views/schema.py Thu Nov 19 12:55:47 2009 +0100
@@ -357,13 +357,11 @@
def should_display_schema(self, rschema):
return (super(RestrictedSchemaVisitorMixIn, self).should_display_schema(rschema)
- and (rschema.has_local_role('read')
- or rschema.has_perm(self.req, 'read')))
+ and rschema.may_have_permission('read', self.req))
- def should_display_attr(self, rschema):
+ def should_display_attr(self, eschema, rschema):
return (super(RestrictedSchemaVisitorMixIn, self).should_display_attr(rschema)
- and (rschema.has_local_role('read')
- or rschema.has_perm(self.req, 'read')))
+ and eschema.rdef(rschema).may_have_permission('read'))
class FullSchemaVisitor(RestrictedSchemaVisitorMixIn, s2d.FullSchemaVisitor):
--- a/web/views/startup.py Wed Nov 18 09:16:38 2009 +0100
+++ b/web/views/startup.py Thu Nov 19 12:55:47 2009 +0100
@@ -26,6 +26,8 @@
@classmethod
def vreg_initialization_completed(cls):
for eschema in cls.schema.entities():
+ if eschema.final:
+ continue
if eschema.schema_entity():
uicfg.indexview_etype_section.setdefault(eschema, 'schema')
elif eschema.is_subobject(strict=True):
@@ -140,8 +142,7 @@
"""
req = self.req
for eschema in eschemas:
- if eschema.final or (not eschema.has_perm(req, 'read') and
- not eschema.has_local_role('read')):
+ if eschema.final or not eschema.may_have_permission('read', req):
continue
etype = eschema.type
label = display_name(req, etype, 'plural')