266 |
266 |
267 from logging import getLogger |
267 from logging import getLogger |
268 from cubicweb import set_log_methods |
268 from cubicweb import set_log_methods |
269 set_log_methods(HooksManager, getLogger('cubicweb.hooksmanager')) |
269 set_log_methods(HooksManager, getLogger('cubicweb.hooksmanager')) |
270 set_log_methods(Hook, getLogger('cubicweb.hooks')) |
270 set_log_methods(Hook, getLogger('cubicweb.hooks')) |
|
271 |
|
272 # base classes for relation propagation ######################################## |
|
273 |
|
274 from cubicweb.server.pool import PreCommitOperation |
|
275 |
|
276 class RQLPrecommitOperation(PreCommitOperation): |
|
277 def precommit_event(self): |
|
278 execute = self.session.unsafe_execute |
|
279 for rql in self.rqls: |
|
280 execute(*rql) |
|
281 |
|
282 |
|
283 class PropagateSubjectRelationHook(Hook): |
|
284 """propagate permissions and nosy list when new entity are added""" |
|
285 events = ('after_add_relation',) |
|
286 # to set in concrete class |
|
287 rtype = None |
|
288 subject_relations = None |
|
289 object_relations = None |
|
290 accepts = None # subject_relations + object_relations |
|
291 |
|
292 def call(self, session, fromeid, rtype, toeid): |
|
293 for eid in (fromeid, toeid): |
|
294 etype = session.describe(eid)[0] |
|
295 if not self.schema.eschema(etype).has_subject_relation(self.rtype): |
|
296 return |
|
297 if rtype in self.subject_relations: |
|
298 meid, seid = fromeid, toeid |
|
299 else: |
|
300 assert rtype in self.object_relations |
|
301 meid, seid = toeid, fromeid |
|
302 rql = 'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'\ |
|
303 % (self.rtype, self.rtype, self.rtype) |
|
304 rqls = [(rql, {'x': meid, 'e': seid}, ('x', 'e'))] |
|
305 RQLPrecommitOperation(session, rqls=rqls) |
|
306 |
|
307 |
|
308 class PropagateSubjectRelationAddHook(Hook): |
|
309 """propagate on existing entities when a permission or nosy list is added""" |
|
310 events = ('after_add_relation',) |
|
311 # to set in concrete class |
|
312 rtype = None |
|
313 subject_relations = None |
|
314 object_relations = None |
|
315 accepts = None # (self.rtype,) |
|
316 |
|
317 def call(self, session, fromeid, rtype, toeid): |
|
318 eschema = self.schema.eschema(session.describe(fromeid)[0]) |
|
319 rqls = [] |
|
320 for rel in self.subject_relations: |
|
321 if eschema.has_subject_relation(rel): |
|
322 rqls.append(('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
|
323 'X %s R, NOT R %s P' % (rtype, rel, rtype), |
|
324 {'x': fromeid, 'p': toeid}, 'x')) |
|
325 for rel in self.object_relations: |
|
326 if eschema.has_object_relation(rel): |
|
327 rqls.append(('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
|
328 'R %s X, NOT R %s P' % (rtype, rel, rtype), |
|
329 {'x': fromeid, 'p': toeid}, 'x')) |
|
330 if rqls: |
|
331 RQLPrecommitOperation(session, rqls=rqls) |
|
332 |
|
333 |
|
334 class PropagateSubjectRelationDelHook(Hook): |
|
335 """propagate on existing entities when a permission is deleted""" |
|
336 events = ('after_delete_relation',) |
|
337 # to set in concrete class |
|
338 rtype = None |
|
339 subject_relations = None |
|
340 object_relations = None |
|
341 accepts = None # (self.rtype,) |
|
342 |
|
343 def call(self, session, fromeid, rtype, toeid): |
|
344 eschema = self.schema.eschema(session.describe(fromeid)[0]) |
|
345 rqls = [] |
|
346 for rel in self.subject_relations: |
|
347 if eschema.has_subject_relation(rel): |
|
348 rqls.append(('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
|
349 'X %s R' % (rtype, rel), |
|
350 {'x': fromeid, 'p': toeid}, 'x')) |
|
351 for rel in self.object_relations: |
|
352 if eschema.has_object_relation(rel): |
|
353 rqls.append(('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
|
354 'R %s X' % (rtype, rel), |
|
355 {'x': fromeid, 'p': toeid}, 'x')) |
|
356 if rqls: |
|
357 RQLPrecommitOperation(session, rqls=rqls) |