142 rschema = eschema.subjrels[attr] |
142 rschema = eschema.subjrels[attr] |
143 except KeyError: |
143 except KeyError: |
144 cls.warning('skipping fetch_attr %s defined in %s (not found in schema)', |
144 cls.warning('skipping fetch_attr %s defined in %s (not found in schema)', |
145 attr, cls.__regid__) |
145 attr, cls.__regid__) |
146 continue |
146 continue |
147 if not user.matching_groups(rschema.get_groups('read')): |
147 rdef = eschema.rdef(attr) |
|
148 if not user.matching_groups(rdef.get_groups('read')): |
148 continue |
149 continue |
149 var = varmaker.next() |
150 var = varmaker.next() |
150 selection.append(var) |
151 selection.append(var) |
151 restriction = '%s %s %s' % (mainvar, attr, var) |
152 restriction = '%s %s %s' % (mainvar, attr, var) |
152 restrictions.append(restriction) |
153 restrictions.append(restriction) |
153 if not rschema.final: |
154 if not rschema.final: |
154 # XXX this does not handle several destination types |
155 # XXX this does not handle several destination types |
155 desttype = rschema.objects(eschema.type)[0] |
156 desttype = rschema.objects(eschema.type)[0] |
156 card = rschema.rproperty(eschema, desttype, 'cardinality')[0] |
157 card = rdef.cardinality[0] |
157 if card not in '?1': |
158 if card not in '?1': |
158 cls.warning('bad relation %s specified in fetch attrs for %s', |
159 cls.warning('bad relation %s specified in fetch attrs for %s', |
159 attr, cls) |
160 attr, cls) |
160 selection.pop() |
161 selection.pop() |
161 restrictions.pop() |
162 restrictions.pop() |
254 def clear_local_perm_cache(self, action): |
255 def clear_local_perm_cache(self, action): |
255 for rqlexpr in self.e_schema.get_rqlexprs(action): |
256 for rqlexpr in self.e_schema.get_rqlexprs(action): |
256 self._cw.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None) |
257 self._cw.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None) |
257 |
258 |
258 def check_perm(self, action): |
259 def check_perm(self, action): |
259 self.e_schema.check_perm(self._cw, action, self.eid) |
260 self.e_schema.check_perm(self._cw, action, eid=self.eid) |
260 |
261 |
261 def has_perm(self, action): |
262 def has_perm(self, action): |
262 return self.e_schema.has_perm(self._cw, action, self.eid) |
263 return self.e_schema.has_perm(self._cw, action, eid=self.eid) |
263 |
264 |
264 def view(self, vid, __registry='views', **kwargs): |
265 def view(self, vid, __registry='views', **kwargs): |
265 """shortcut to apply a view on this entity""" |
266 """shortcut to apply a view on this entity""" |
266 view = self._cw.vreg[__registry].select(vid, self._cw, rset=self.cw_rset, |
267 view = self._cw.vreg[__registry].select(vid, self._cw, rset=self.cw_rset, |
267 row=self.cw_row, col=self.cw_col, |
268 row=self.cw_row, col=self.cw_col, |
337 value = value.strip() |
338 value = value.strip() |
338 if value is None or value == '': # don't use "not", 0 is an acceptable value |
339 if value is None or value == '': # don't use "not", 0 is an acceptable value |
339 return u'' |
340 return u'' |
340 if attrtype is None: |
341 if attrtype is None: |
341 attrtype = self.e_schema.destination(attr) |
342 attrtype = self.e_schema.destination(attr) |
342 props = self.e_schema.rproperties(attr) |
343 props = self.e_schema.rdef(attr) |
343 if attrtype == 'String': |
344 if attrtype == 'String': |
344 # internalinalized *and* formatted string such as schema |
345 # internalinalized *and* formatted string such as schema |
345 # description... |
346 # description... |
346 if props.get('internationalizable'): |
347 if props.internationalizable: |
347 value = self._cw._(value) |
348 value = self._cw._(value) |
348 attrformat = self.attr_metadata(attr, 'format') |
349 attrformat = self.attr_metadata(attr, 'format') |
349 if attrformat: |
350 if attrformat: |
350 return self.mtc_transform(value, attrformat, format, |
351 return self.mtc_transform(value, attrformat, format, |
351 self._cw.encoding) |
352 self._cw.encoding) |
389 if getattr(self, rschema.type): |
390 if getattr(self, rschema.type): |
390 continue |
391 continue |
391 if rschema.type in self.skip_copy_for: |
392 if rschema.type in self.skip_copy_for: |
392 continue |
393 continue |
393 # skip composite relation |
394 # skip composite relation |
394 if self.e_schema.subjrproperty(rschema, 'composite'): |
395 rdef = self.e_schema.rdef(rschema) |
|
396 if rdef.composite: |
395 continue |
397 continue |
396 # skip relation with card in ?1 else we either change the copied |
398 # skip relation with card in ?1 else we either change the copied |
397 # object (inlined relation) or inserting some inconsistency |
399 # object (inlined relation) or inserting some inconsistency |
398 if self.e_schema.subjrproperty(rschema, 'cardinality')[1] in '?1': |
400 if rdef.cardinality[1] in '?1': |
399 continue |
401 continue |
400 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
402 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
401 rschema.type, rschema.type) |
403 rschema.type, rschema.type) |
402 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
404 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
403 self.clear_related_cache(rschema.type, 'subject') |
405 self.clear_related_cache(rschema.type, 'subject') |
404 for rschema in self.e_schema.object_relations(): |
406 for rschema in self.e_schema.object_relations(): |
405 if rschema.meta: |
407 if rschema.meta: |
406 continue |
408 continue |
407 # skip already defined relations |
409 # skip already defined relations |
408 if getattr(self, 'reverse_%s' % rschema.type): |
410 if self.related(rschema.type, 'object'): |
409 continue |
411 continue |
|
412 rdef = self.e_schema.rdef(rschema, 'object') |
410 # skip composite relation |
413 # skip composite relation |
411 if self.e_schema.objrproperty(rschema, 'composite'): |
414 if rdef.composite: |
412 continue |
415 continue |
413 # skip relation with card in ?1 else we either change the copied |
416 # skip relation with card in ?1 else we either change the copied |
414 # object (inlined relation) or inserting some inconsistency |
417 # object (inlined relation) or inserting some inconsistency |
415 if self.e_schema.objrproperty(rschema, 'cardinality')[0] in '?1': |
418 if rdef.cardinality[0] in '?1': |
416 continue |
419 continue |
417 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
420 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
418 rschema.type, rschema.type) |
421 rschema.type, rschema.type) |
419 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
422 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
420 self.clear_related_cache(rschema.type, 'object') |
423 self.clear_related_cache(rschema.type, 'object') |
431 def to_complete_relations(self): |
434 def to_complete_relations(self): |
432 """by default complete final relations to when calling .complete()""" |
435 """by default complete final relations to when calling .complete()""" |
433 for rschema in self.e_schema.subject_relations(): |
436 for rschema in self.e_schema.subject_relations(): |
434 if rschema.final: |
437 if rschema.final: |
435 continue |
438 continue |
436 if len(rschema.objects(self.e_schema)) > 1: |
439 targets = rschema.objects(self.e_schema) |
|
440 if len(targets) > 1: |
437 # ambigous relations, the querier doesn't handle |
441 # ambigous relations, the querier doesn't handle |
438 # outer join correctly in this case |
442 # outer join correctly in this case |
439 continue |
443 continue |
440 if rschema.inlined: |
444 if rschema.inlined: |
441 matching_groups = self._cw.user.matching_groups |
445 matching_groups = self._cw.user.matching_groups |
442 if matching_groups(rschema.get_groups('read')) and \ |
446 rdef = rschema.rdef(self.e_schema, targets[0]) |
443 all(matching_groups(es.get_groups('read')) |
447 if matching_groups(rdef.get_groups('read')) and \ |
444 for es in rschema.objects(self.e_schema)): |
448 all(matching_groups(e.get_groups('read')) for e in targets): |
445 yield rschema, 'subject' |
449 yield rschema, 'subject' |
446 |
450 |
447 def to_complete_attributes(self, skip_bytes=True): |
451 def to_complete_attributes(self, skip_bytes=True): |
448 for rschema, attrschema in self.e_schema.attribute_definitions(): |
452 for rschema, attrschema in self.e_schema.attribute_definitions(): |
449 # skip binary data by default |
453 # skip binary data by default |
487 for rschema, role in self.to_complete_relations(): |
492 for rschema, role in self.to_complete_relations(): |
488 rtype = rschema.type |
493 rtype = rschema.type |
489 if self.relation_cached(rtype, role): |
494 if self.relation_cached(rtype, role): |
490 continue |
495 continue |
491 var = varmaker.next() |
496 var = varmaker.next() |
|
497 targettype = rschema.targets(self.e_schema, role)[0] |
|
498 rdef = rschema.role_rdef(self.e_schema, targettype, role) |
|
499 card = rdef.role_cardinality(role) |
|
500 assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype, |
|
501 role, card) |
492 if role == 'subject': |
502 if role == 'subject': |
493 targettype = rschema.objects(self.e_schema)[0] |
|
494 card = rschema.rproperty(self.e_schema, targettype, |
|
495 'cardinality')[0] |
|
496 if card == '1': |
503 if card == '1': |
497 rql.append('%s %s %s' % (V, rtype, var)) |
504 rql.append('%s %s %s' % (V, rtype, var)) |
498 else: # '?" |
505 else: |
499 rql.append('%s %s %s?' % (V, rtype, var)) |
506 rql.append('%s %s %s?' % (V, rtype, var)) |
500 else: |
507 else: |
501 targettype = rschema.subjects(self.e_schema)[1] |
|
502 card = rschema.rproperty(self.e_schema, targettype, |
|
503 'cardinality')[1] |
|
504 if card == '1': |
508 if card == '1': |
505 rql.append('%s %s %s' % (var, rtype, V)) |
509 rql.append('%s %s %s' % (var, rtype, V)) |
506 else: # '?" |
510 else: |
507 rql.append('%s? %s %s' % (var, rtype, V)) |
511 rql.append('%s? %s %s' % (var, rtype, V)) |
508 assert card in '1?', '%s %s %s %s' % (self.e_schema, rtype, |
|
509 role, card) |
|
510 selected.append(((rtype, role), var)) |
512 selected.append(((rtype, role), var)) |
511 if selected: |
513 if selected: |
512 # select V, we need it as the left most selected variable |
514 # select V, we need it as the left most selected variable |
513 # if some outer join are included to fetch inlined relations |
515 # if some outer join are included to fetch inlined relations |
514 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
516 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
650 securitycheck_args = {'toeid': self.eid} |
652 securitycheck_args = {'toeid': self.eid} |
651 else: |
653 else: |
652 restriction = [] |
654 restriction = [] |
653 args = {} |
655 args = {} |
654 securitycheck_args = {} |
656 securitycheck_args = {} |
655 insertsecurity = (rtype.has_local_role('add') and not |
657 rdef = rtype.role_rdef(self.e_schema, targettype, role) |
656 rtype.has_perm(self._cw, 'add', **securitycheck_args)) |
658 insertsecurity = (rdef.has_local_role('add') and not |
657 constraints = rtype.rproperty(subjtype, objtype, 'constraints') |
659 rdef.has_perm(self._cw, 'add', **securitycheck_args)) |
658 if vocabconstraints: |
660 if vocabconstraints: |
659 # RQLConstraint is a subclass for RQLVocabularyConstraint, so they |
661 # RQLConstraint is a subclass for RQLVocabularyConstraint, so they |
660 # will be included as well |
662 # will be included as well |
661 restriction += [cstr.restriction for cstr in constraints |
663 restriction += [cstr.restriction for cstr in rdef.constraints |
662 if isinstance(cstr, RQLVocabularyConstraint)] |
664 if isinstance(cstr, RQLVocabularyConstraint)] |
663 else: |
665 else: |
664 restriction += [cstr.restriction for cstr in constraints |
666 restriction += [cstr.restriction for cstr in rdef.constraints |
665 if isinstance(cstr, RQLConstraint)] |
667 if isinstance(cstr, RQLConstraint)] |
666 etypecls = self._cw.vreg['etypes'].etype_class(targettype) |
668 etypecls = self._cw.vreg['etypes'].etype_class(targettype) |
667 rql = etypecls.fetch_rql(self._cw.user, restriction, |
669 rql = etypecls.fetch_rql(self._cw.user, restriction, |
668 mainvar=searchedvar, ordermethod=ordermethod) |
670 mainvar=searchedvar, ordermethod=ordermethod) |
669 # ensure we have an order defined |
671 # ensure we have an order defined |
670 if not ' ORDERBY ' in rql: |
672 if not ' ORDERBY ' in rql: |
671 before, after = rql.split(' WHERE ', 1) |
673 before, after = rql.split(' WHERE ', 1) |
672 rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after) |
674 rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after) |
673 if insertsecurity: |
675 if insertsecurity: |
674 rqlexprs = rtype.get_rqlexprs('add') |
676 rqlexprs = rdef.get_rqlexprs('add') |
675 rewriter = RQLRewriter(self._cw) |
677 rewriter = RQLRewriter(self._cw) |
676 rqlst = self._cw.vreg.parse(self._cw, rql, args) |
678 rqlst = self._cw.vreg.parse(self._cw, rql, args) |
|
679 if not self.has_eid(): |
|
680 existant = searchedvar |
|
681 else: |
|
682 existant = None # instead of 'SO', improve perfs |
677 for select in rqlst.children: |
683 for select in rqlst.children: |
678 rewriter.rewrite(select, [((searchedvar, searchedvar), rqlexprs)], |
684 rewriter.rewrite(select, [((searchedvar, searchedvar), rqlexprs)], |
679 select.solutions, args) |
685 select.solutions, args, existant) |
680 rql = rqlst.as_string() |
686 rql = rqlst.as_string() |
681 return rql, args |
687 return rql, args |
682 |
688 |
683 def unrelated(self, rtype, targettype, role='subject', limit=None, |
689 def unrelated(self, rtype, targettype, role='subject', limit=None, |
684 ordermethod=None): |
690 ordermethod=None): |
717 """set cached values for the given relation""" |
723 """set cached values for the given relation""" |
718 if rset: |
724 if rset: |
719 related = list(rset.entities(col)) |
725 related = list(rset.entities(col)) |
720 rschema = self._cw.vreg.schema.rschema(rtype) |
726 rschema = self._cw.vreg.schema.rschema(rtype) |
721 if role == 'subject': |
727 if role == 'subject': |
722 rcard = rschema.rproperty(self.e_schema, related[0].e_schema, |
728 rcard = rschema.rdef(self.e_schema, related[0].e_schema).cardinality[1] |
723 'cardinality')[1] |
|
724 target = 'object' |
729 target = 'object' |
725 else: |
730 else: |
726 rcard = rschema.rproperty(related[0].e_schema, self.e_schema, |
731 rcard = rschema.rdef(related[0].e_schema, self.e_schema).cardinality[0] |
727 'cardinality')[0] |
|
728 target = 'subject' |
732 target = 'subject' |
729 if rcard in '?1': |
733 if rcard in '?1': |
730 for rentity in related: |
734 for rentity in related: |
731 rentity._related_cache['%s_%s' % (rtype, target)] = ( |
735 rentity._related_cache['%s_%s' % (rtype, target)] = ( |
732 self.as_rset(), (self,)) |
736 self.as_rset(), (self,)) |