entity.py
branchreldefsecurity
changeset 3877 7ca53fc72a0a
parent 3826 0c0c051863cb
child 3890 d7a270f50f54
equal deleted inserted replaced
3876:1169d3154be6 3877:7ca53fc72a0a
    32 _marker = object()
    32 _marker = object()
    33 
    33 
    34 def greater_card(rschema, subjtypes, objtypes, index):
    34 def greater_card(rschema, subjtypes, objtypes, index):
    35     for subjtype in subjtypes:
    35     for subjtype in subjtypes:
    36         for objtype in objtypes:
    36         for objtype in objtypes:
    37             card = rschema.rproperty(subjtype, objtype, 'cardinality')[index]
    37             card = rschema.rdef(subjtype, objtype).cardinality[index]
    38             if card in '+*':
    38             if card in '+*':
    39                 return card
    39                 return card
    40     return '1'
    40     return '1'
    41 
    41 
    42 
    42 
   241                 rschema = eschema.subjrels[attr]
   241                 rschema = eschema.subjrels[attr]
   242             except KeyError:
   242             except KeyError:
   243                 cls.warning('skipping fetch_attr %s defined in %s (not found in schema)',
   243                 cls.warning('skipping fetch_attr %s defined in %s (not found in schema)',
   244                             attr, cls.id)
   244                             attr, cls.id)
   245                 continue
   245                 continue
   246             if not user.matching_groups(rschema.get_groups('read')):
   246             rdef = eschema.rdef(attr)
       
   247             if not user.matching_groups(rdef.get_groups('read')):
   247                 continue
   248                 continue
   248             var = varmaker.next()
   249             var = varmaker.next()
   249             selection.append(var)
   250             selection.append(var)
   250             restriction = '%s %s %s' % (mainvar, attr, var)
   251             restriction = '%s %s %s' % (mainvar, attr, var)
   251             restrictions.append(restriction)
   252             restrictions.append(restriction)
   252             if not rschema.final:
   253             if not rschema.final:
   253                 # XXX this does not handle several destination types
   254                 # XXX this does not handle several destination types
   254                 desttype = rschema.objects(eschema.type)[0]
   255                 desttype = rschema.objects(eschema.type)[0]
   255                 card = rschema.rproperty(eschema, desttype, 'cardinality')[0]
   256                 card = rdef.cardinality[0]
   256                 if card not in '?1':
   257                 if card not in '?1':
   257                     cls.warning('bad relation %s specified in fetch attrs for %s',
   258                     cls.warning('bad relation %s specified in fetch attrs for %s',
   258                                  attr, cls)
   259                                  attr, cls)
   259                     selection.pop()
   260                     selection.pop()
   260                     restrictions.pop()
   261                     restrictions.pop()
   360     def clear_local_perm_cache(self, action):
   361     def clear_local_perm_cache(self, action):
   361         for rqlexpr in self.e_schema.get_rqlexprs(action):
   362         for rqlexpr in self.e_schema.get_rqlexprs(action):
   362             self.req.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None)
   363             self.req.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None)
   363 
   364 
   364     def check_perm(self, action):
   365     def check_perm(self, action):
   365         self.e_schema.check_perm(self.req, action, self.eid)
   366         self.e_schema.check_perm(self.req, action, eid=self.eid)
   366 
   367 
   367     def has_perm(self, action):
   368     def has_perm(self, action):
   368         return self.e_schema.has_perm(self.req, action, self.eid)
   369         return self.e_schema.has_perm(self.req, action, eid=self.eid)
   369 
   370 
   370     def view(self, vid, __registry='views', **kwargs):
   371     def view(self, vid, __registry='views', **kwargs):
   371         """shortcut to apply a view on this entity"""
   372         """shortcut to apply a view on this entity"""
   372         return self.vreg[__registry].render(vid, self.req, rset=self.rset,
   373         return self.vreg[__registry].render(vid, self.req, rset=self.rset,
   373                                             row=self.row, col=self.col, **kwargs)
   374                                             row=self.row, col=self.col, **kwargs)
   441             value = value.strip()
   442             value = value.strip()
   442         if value is None or value == '': # don't use "not", 0 is an acceptable value
   443         if value is None or value == '': # don't use "not", 0 is an acceptable value
   443             return u''
   444             return u''
   444         if attrtype is None:
   445         if attrtype is None:
   445             attrtype = self.e_schema.destination(attr)
   446             attrtype = self.e_schema.destination(attr)
   446         props = self.e_schema.rproperties(attr)
   447         props = self.e_schema.rdef(attr)
   447         if attrtype == 'String':
   448         if attrtype == 'String':
   448             # internalinalized *and* formatted string such as schema
   449             # internalinalized *and* formatted string such as schema
   449             # description...
   450             # description...
   450             if props.get('internationalizable'):
   451             if props.internationalizable:
   451                 value = self.req._(value)
   452                 value = self.req._(value)
   452             attrformat = self.attr_metadata(attr, 'format')
   453             attrformat = self.attr_metadata(attr, 'format')
   453             if attrformat:
   454             if attrformat:
   454                 return self.mtc_transform(value, attrformat, format,
   455                 return self.mtc_transform(value, attrformat, format,
   455                                           self.req.encoding)
   456                                           self.req.encoding)
   493             if getattr(self, rschema.type):
   494             if getattr(self, rschema.type):
   494                 continue
   495                 continue
   495             if rschema.type in self.skip_copy_for:
   496             if rschema.type in self.skip_copy_for:
   496                 continue
   497                 continue
   497             # skip composite relation
   498             # skip composite relation
   498             if self.e_schema.subjrproperty(rschema, 'composite'):
   499             rdef = self.e_schema.rdef(rschema)
       
   500             if rdef.composite:
   499                 continue
   501                 continue
   500             # skip relation with card in ?1 else we either change the copied
   502             # skip relation with card in ?1 else we either change the copied
   501             # object (inlined relation) or inserting some inconsistency
   503             # object (inlined relation) or inserting some inconsistency
   502             if self.e_schema.subjrproperty(rschema, 'cardinality')[1] in '?1':
   504             if rdef.cardinality[1] in '?1':
   503                 continue
   505                 continue
   504             rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % (
   506             rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % (
   505                 rschema.type, rschema.type)
   507                 rschema.type, rschema.type)
   506             execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
   508             execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
   507             self.clear_related_cache(rschema.type, 'subject')
   509             self.clear_related_cache(rschema.type, 'subject')
   508         for rschema in self.e_schema.object_relations():
   510         for rschema in self.e_schema.object_relations():
   509             if rschema.meta:
   511             if rschema.meta:
   510                 continue
   512                 continue
   511             # skip already defined relations
   513             # skip already defined relations
   512             if getattr(self, 'reverse_%s' % rschema.type):
   514             if self.related(rschema.type, 'object'):
   513                 continue
   515                 continue
       
   516             rdef = self.e_schema.rdef(rschema, 'object')
   514             # skip composite relation
   517             # skip composite relation
   515             if self.e_schema.objrproperty(rschema, 'composite'):
   518             if rdef.composite:
   516                 continue
   519                 continue
   517             # skip relation with card in ?1 else we either change the copied
   520             # skip relation with card in ?1 else we either change the copied
   518             # object (inlined relation) or inserting some inconsistency
   521             # object (inlined relation) or inserting some inconsistency
   519             if self.e_schema.objrproperty(rschema, 'cardinality')[0] in '?1':
   522             if rdef.cardinality[0] in '?1':
   520                 continue
   523                 continue
   521             rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % (
   524             rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % (
   522                 rschema.type, rschema.type)
   525                 rschema.type, rschema.type)
   523             execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
   526             execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
   524             self.clear_related_cache(rschema.type, 'object')
   527             self.clear_related_cache(rschema.type, 'object')
   535     def to_complete_relations(self):
   538     def to_complete_relations(self):
   536         """by default complete final relations to when calling .complete()"""
   539         """by default complete final relations to when calling .complete()"""
   537         for rschema in self.e_schema.subject_relations():
   540         for rschema in self.e_schema.subject_relations():
   538             if rschema.final:
   541             if rschema.final:
   539                 continue
   542                 continue
   540             if len(rschema.objects(self.e_schema)) > 1:
   543             targets = rschema.objects(self.e_schema)
       
   544             if len(targets) > 1:
   541                 # ambigous relations, the querier doesn't handle
   545                 # ambigous relations, the querier doesn't handle
   542                 # outer join correctly in this case
   546                 # outer join correctly in this case
   543                 continue
   547                 continue
   544             if rschema.inlined:
   548             if rschema.inlined:
       
   549                 rdef = rschema.rdef(self.e_schema, targets[0])
   545                 matching_groups = self.req.user.matching_groups
   550                 matching_groups = self.req.user.matching_groups
   546                 if matching_groups(rschema.get_groups('read')) and \
   551                 if matching_groups(rdef.get_groups('read')) and \
   547                    all(matching_groups(es.get_groups('read'))
   552                    all(matching_groups(e.get_groups('read')) for e in targets):
   548                        for es in rschema.objects(self.e_schema)):
       
   549                     yield rschema, 'subject'
   553                     yield rschema, 'subject'
   550 
   554 
   551     def to_complete_attributes(self, skip_bytes=True):
   555     def to_complete_attributes(self, skip_bytes=True):
   552         for rschema, attrschema in self.e_schema.attribute_definitions():
   556         for rschema, attrschema in self.e_schema.attribute_definitions():
   553             # skip binary data by default
   557             # skip binary data by default
   555                 continue
   559                 continue
   556             attr = rschema.type
   560             attr = rschema.type
   557             if attr == 'eid':
   561             if attr == 'eid':
   558                 continue
   562                 continue
   559             # password retreival is blocked at the repository server level
   563             # password retreival is blocked at the repository server level
   560             if not self.req.user.matching_groups(rschema.get_groups('read')) \
   564             rdef = rschema.rdef(self.e_schema, attrschema)
       
   565             if not self.req.user.matching_groups(rdef.get_groups('read')) \
   561                    or attrschema.type == 'Password':
   566                    or attrschema.type == 'Password':
   562                 self[attr] = None
   567                 self[attr] = None
   563                 continue
   568                 continue
   564             yield attr
   569             yield attr
   565 
   570 
   591             for rschema, role in self.to_complete_relations():
   596             for rschema, role in self.to_complete_relations():
   592                 rtype = rschema.type
   597                 rtype = rschema.type
   593                 if self.relation_cached(rtype, role):
   598                 if self.relation_cached(rtype, role):
   594                     continue
   599                     continue
   595                 var = varmaker.next()
   600                 var = varmaker.next()
       
   601                 targettype = rschema.targets(self.e_schema, role)[0]
       
   602                 rdef = rschema.role_rdef(self.e_schema, targettype, role)
       
   603                 card = rdef.role_cardinality(role)
       
   604                 assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype,
       
   605                                                       role, card)
   596                 if role == 'subject':
   606                 if role == 'subject':
   597                     targettype = rschema.objects(self.e_schema)[0]
       
   598                     card = rschema.rproperty(self.e_schema, targettype,
       
   599                                              'cardinality')[0]
       
   600                     if card == '1':
   607                     if card == '1':
   601                         rql.append('%s %s %s' % (V, rtype, var))
   608                         rql.append('%s %s %s' % (V, rtype, var))
   602                     else: # '?"
   609                     else:
   603                         rql.append('%s %s %s?' % (V, rtype, var))
   610                         rql.append('%s %s %s?' % (V, rtype, var))
   604                 else:
   611                 else:
   605                     targettype = rschema.subjects(self.e_schema)[1]
       
   606                     card = rschema.rproperty(self.e_schema, targettype,
       
   607                                              'cardinality')[1]
       
   608                     if card == '1':
   612                     if card == '1':
   609                         rql.append('%s %s %s' % (var, rtype, V))
   613                         rql.append('%s %s %s' % (var, rtype, V))
   610                     else: # '?"
   614                     else:
   611                         rql.append('%s? %s %s' % (var, rtype, V))
   615                         rql.append('%s? %s %s' % (var, rtype, V))
   612                 assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype,
       
   613                                                       role, card)
       
   614                 selected.append(((rtype, role), var))
   616                 selected.append(((rtype, role), var))
   615         if selected:
   617         if selected:
   616             # select V, we need it as the left most selected variable
   618             # select V, we need it as the left most selected variable
   617             # if some outer join are included to fetch inlined relations
   619             # if some outer join are included to fetch inlined relations
   618             rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected),
   620             rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected),
   754                 securitycheck_args = {'toeid': self.eid}
   756                 securitycheck_args = {'toeid': self.eid}
   755         else:
   757         else:
   756             restriction = []
   758             restriction = []
   757             args = {}
   759             args = {}
   758             securitycheck_args = {}
   760             securitycheck_args = {}
   759         insertsecurity = (rtype.has_local_role('add') and not
   761         rdef = rtype.role_rdef(self.e_schema, targettype, role)
   760                           rtype.has_perm(self.req, 'add', **securitycheck_args))
   762         insertsecurity = (rdef.has_local_role('add') and not
   761         constraints = rtype.rproperty(subjtype, objtype, 'constraints')
   763                           rdef.has_perm(self.req, 'add', **securitycheck_args))
   762         if vocabconstraints:
   764         if vocabconstraints:
   763             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
   765             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
   764             # will be included as well
   766             # will be included as well
   765             restriction += [cstr.restriction for cstr in constraints
   767             restriction += [cstr.restriction for cstr in rdef.constraints
   766                             if isinstance(cstr, RQLVocabularyConstraint)]
   768                             if isinstance(cstr, RQLVocabularyConstraint)]
   767         else:
   769         else:
   768             restriction += [cstr.restriction for cstr in constraints
   770             restriction += [cstr.restriction for cstr in rdef.constraints
   769                             if isinstance(cstr, RQLConstraint)]
   771                             if isinstance(cstr, RQLConstraint)]
   770         etypecls = self.vreg['etypes'].etype_class(targettype)
   772         etypecls = self.vreg['etypes'].etype_class(targettype)
   771         rql = etypecls.fetch_rql(self.req.user, restriction,
   773         rql = etypecls.fetch_rql(self.req.user, restriction,
   772                                  mainvar=searchedvar, ordermethod=ordermethod)
   774                                  mainvar=searchedvar, ordermethod=ordermethod)
   773         # ensure we have an order defined
   775         # ensure we have an order defined
   774         if not ' ORDERBY ' in rql:
   776         if not ' ORDERBY ' in rql:
   775             before, after = rql.split(' WHERE ', 1)
   777             before, after = rql.split(' WHERE ', 1)
   776             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
   778             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
   777         if insertsecurity:
   779         if insertsecurity:
   778             rqlexprs = rtype.get_rqlexprs('add')
   780             rqlexprs = rdef.get_rqlexprs('add')
   779             rewriter = RQLRewriter(self.req)
   781             rewriter = RQLRewriter(self.req)
   780             rqlst = self.req.vreg.parse(self.req, rql, args)
   782             rqlst = self.req.vreg.parse(self.req, rql, args)
   781             if not self.has_eid():
   783             if not self.has_eid():
   782                 existant = searchedvar
   784                 existant = searchedvar
   783             else:
   785             else:
   825         """set cached values for the given relation"""
   827         """set cached values for the given relation"""
   826         if rset:
   828         if rset:
   827             related = tuple(rset.entities(col))
   829             related = tuple(rset.entities(col))
   828             rschema = self.schema.rschema(rtype)
   830             rschema = self.schema.rschema(rtype)
   829             if role == 'subject':
   831             if role == 'subject':
   830                 rcard = rschema.rproperty(self.e_schema, related[0].e_schema,
   832                 rcard = rschema.rdef(self.e_schema, related[0].e_schema).cardinality[1]
   831                                           'cardinality')[1]
       
   832                 target = 'object'
   833                 target = 'object'
   833             else:
   834             else:
   834                 rcard = rschema.rproperty(related[0].e_schema, self.e_schema,
   835                 rcard = rschema.rdef(related[0].e_schema, self.e_schema).cardinality[0]
   835                                           'cardinality')[0]
       
   836                 target = 'subject'
   836                 target = 'subject'
   837             if rcard in '?1':
   837             if rcard in '?1':
   838                 for rentity in related:
   838                 for rentity in related:
   839                     rentity._related_cache['%s_%s' % (rtype, target)] = (
   839                     rentity._related_cache['%s_%s' % (rtype, target)] = (
   840                         self.as_rset(), (self,))
   840                         self.as_rset(), (self,))