# HG changeset patch # User Sylvain Thénault # Date 1250675335 -7200 # Node ID 452b4c9ee61d89fc42a377c1eeddbeb35bf1900b # Parent 9a243ba71260990a6fd1a242d59305081ad9f3b7 work in progress: backport some generic relation propagation hooks from tracker diff -r 9a243ba71260 -r 452b4c9ee61d server/hooksmanager.py --- a/server/hooksmanager.py Wed Aug 19 08:32:18 2009 +0200 +++ b/server/hooksmanager.py Wed Aug 19 11:48:55 2009 +0200 @@ -268,3 +268,90 @@ from cubicweb import set_log_methods set_log_methods(HooksManager, getLogger('cubicweb.hooksmanager')) set_log_methods(Hook, getLogger('cubicweb.hooks')) + +# base classes for relation propagation ######################################## + +from cubicweb.server.pool import PreCommitOperation + +class RQLPrecommitOperation(PreCommitOperation): + def precommit_event(self): + execute = self.session.unsafe_execute + for rql in self.rqls: + execute(*rql) + + +class PropagateSubjectRelationHook(Hook): + """propagate permissions and nosy list when new entity are added""" + events = ('after_add_relation',) + # to set in concrete class + rtype = None + subject_relations = None + object_relations = None + accepts = None # subject_relations + object_relations + + def call(self, session, fromeid, rtype, toeid): + for eid in (fromeid, toeid): + etype = session.describe(eid)[0] + if not self.schema.eschema(etype).has_subject_relation(self.rtype): + return + if rtype in self.subject_relations: + meid, seid = fromeid, toeid + else: + assert rtype in self.object_relations + meid, seid = toeid, fromeid + rql = 'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'\ + % (self.rtype, self.rtype, self.rtype) + rqls = [(rql, {'x': meid, 'e': seid}, ('x', 'e'))] + RQLPrecommitOperation(session, rqls=rqls) + + +class PropagateSubjectRelationAddHook(Hook): + """propagate on existing entities when a permission or nosy list is added""" + events = ('after_add_relation',) + # to set in concrete class + rtype = None + subject_relations = None + object_relations = None + accepts = None # (self.rtype,) + + def call(self, session, fromeid, rtype, toeid): + eschema = self.schema.eschema(session.describe(fromeid)[0]) + rqls = [] + for rel in self.subject_relations: + if eschema.has_subject_relation(rel): + rqls.append(('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' + 'X %s R, NOT R %s P' % (rtype, rel, rtype), + {'x': fromeid, 'p': toeid}, 'x')) + for rel in self.object_relations: + if eschema.has_object_relation(rel): + rqls.append(('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' + 'R %s X, NOT R %s P' % (rtype, rel, rtype), + {'x': fromeid, 'p': toeid}, 'x')) + if rqls: + RQLPrecommitOperation(session, rqls=rqls) + + +class PropagateSubjectRelationDelHook(Hook): + """propagate on existing entities when a permission is deleted""" + events = ('after_delete_relation',) + # to set in concrete class + rtype = None + subject_relations = None + object_relations = None + accepts = None # (self.rtype,) + + def call(self, session, fromeid, rtype, toeid): + eschema = self.schema.eschema(session.describe(fromeid)[0]) + rqls = [] + for rel in self.subject_relations: + if eschema.has_subject_relation(rel): + rqls.append(('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' + 'X %s R' % (rtype, rel), + {'x': fromeid, 'p': toeid}, 'x')) + for rel in self.object_relations: + if eschema.has_object_relation(rel): + rqls.append(('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' + 'R %s X' % (rtype, rel), + {'x': fromeid, 'p': toeid}, 'x')) + if rqls: + RQLPrecommitOperation(session, rqls=rqls)