302 """raise an exception if the given rql is not a select query""" |
302 """raise an exception if the given rql is not a select query""" |
303 first = rql.split(' ', 1)[0].lower() |
303 first = rql.split(' ', 1)[0].lower() |
304 if first in ('insert', 'set', 'delete'): |
304 if first in ('insert', 'set', 'delete'): |
305 raise Unauthorized(self.req._('only select queries are authorized')) |
305 raise Unauthorized(self.req._('only select queries are authorized')) |
306 |
306 |
307 # .accepts handling utilities ############################################# |
|
308 |
|
309 accepts = ('Any',) |
|
310 |
|
311 @classmethod |
|
312 def accept_rset(cls, req, rset, row, col): |
|
313 """apply the following rules: |
|
314 * if row is None, return the sum of values returned by the method |
|
315 for each entity's type in the result set. If any score is 0, |
|
316 return 0. |
|
317 * if row is specified, return the value returned by the method with |
|
318 the entity's type of this row |
|
319 """ |
|
320 if row is None: |
|
321 score = 0 |
|
322 for etype in rset.column_types(0): |
|
323 accepted = cls.accept(req.user, etype) |
|
324 if not accepted: |
|
325 return 0 |
|
326 score += accepted |
|
327 return score |
|
328 return cls.accept(req.user, rset.description[row][col or 0]) |
|
329 |
|
330 @classmethod |
|
331 def accept(cls, user, etype): |
|
332 """score etype, returning better score on exact match""" |
|
333 if 'Any' in cls.accepts: |
|
334 return 1 |
|
335 eschema = cls.schema.eschema(etype) |
|
336 matching_types = [e.type for e in eschema.ancestors()] |
|
337 matching_types.append(etype) |
|
338 for index, basetype in enumerate(matching_types): |
|
339 if basetype in cls.accepts: |
|
340 return 2 + index |
|
341 return 0 |
|
342 |
|
343 # .rtype handling utilities ############################################## |
|
344 |
|
345 @classmethod |
|
346 def relation_possible(cls, etype): |
|
347 """tell if a relation with etype entity is possible according to |
|
348 mixed class'.etype, .rtype and .target attributes |
|
349 |
|
350 XXX should probably be moved out to a function |
|
351 """ |
|
352 schema = cls.schema |
|
353 rtype = cls.rtype |
|
354 eschema = schema.eschema(etype) |
|
355 if hasattr(cls, 'role'): |
|
356 role = cls.role |
|
357 elif cls.target == 'subject': |
|
358 role = 'object' |
|
359 else: |
|
360 role = 'subject' |
|
361 # check if this relation is possible according to the schema |
|
362 try: |
|
363 if role == 'object': |
|
364 rschema = eschema.object_relation(rtype) |
|
365 else: |
|
366 rschema = eschema.subject_relation(rtype) |
|
367 except KeyError: |
|
368 return False |
|
369 if hasattr(cls, 'etype'): |
|
370 letype = cls.etype |
|
371 try: |
|
372 if role == 'object': |
|
373 return etype in rschema.objects(letype) |
|
374 else: |
|
375 return etype in rschema.subjects(letype) |
|
376 except KeyError, ex: |
|
377 return False |
|
378 return True |
|
379 |
|
380 |
|
381 # XXX deprecated (since 2.43) ########################## |
|
382 |
|
383 @obsolete('use req.datadir_url') |
|
384 def datadir_url(self): |
|
385 """return url of the application's data directory""" |
|
386 return self.req.datadir_url |
|
387 |
|
388 @obsolete('use req.external_resource()') |
|
389 def external_resource(self, rid, default=_MARKER): |
|
390 return self.req.external_resource(rid, default) |
|
391 |
|
392 |
307 |
393 class AppObject(AppRsetObject): |
308 class AppObject(AppRsetObject): |
394 """base class for application objects which are not selected |
309 """base class for application objects which are not selected |
395 according to a result set, only by their identifier. |
310 according to a result set, only by their identifier. |
396 |
311 |