31 :organization: Logilab |
31 :organization: Logilab |
32 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
32 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
33 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
33 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
34 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
34 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
35 """ |
35 """ |
|
36 from __future__ import with_statement |
|
37 |
36 __docformat__ = "restructuredtext en" |
38 __docformat__ = "restructuredtext en" |
37 |
39 |
38 from warnings import warn |
40 from warnings import warn |
39 from logging import getLogger |
41 from logging import getLogger |
40 from itertools import chain |
42 from itertools import chain |
45 |
47 |
46 from cubicweb.cwvreg import CWRegistry, VRegistry |
48 from cubicweb.cwvreg import CWRegistry, VRegistry |
47 from cubicweb.selectors import (objectify_selector, lltrace, ExpectedValueSelector, |
49 from cubicweb.selectors import (objectify_selector, lltrace, ExpectedValueSelector, |
48 implements) |
50 implements) |
49 from cubicweb.appobject import AppObject |
51 from cubicweb.appobject import AppObject |
50 |
52 from cubicweb.server.session import security_enabled |
51 |
53 |
52 ENTITIES_HOOKS = set(('before_add_entity', 'after_add_entity', |
54 ENTITIES_HOOKS = set(('before_add_entity', 'after_add_entity', |
53 'before_update_entity', 'after_update_entity', |
55 'before_update_entity', 'after_update_entity', |
54 'before_delete_entity', 'after_delete_entity')) |
56 'before_delete_entity', 'after_delete_entity')) |
55 RELATIONS_HOOKS = set(('before_add_relation', 'after_add_relation' , |
57 RELATIONS_HOOKS = set(('before_add_relation', 'after_add_relation' , |
74 if event not in ALL_HOOKS: |
76 if event not in ALL_HOOKS: |
75 raise Exception('bad event %s on %s.%s' % ( |
77 raise Exception('bad event %s on %s.%s' % ( |
76 event, obj.__module__, obj.__name__)) |
78 event, obj.__module__, obj.__name__)) |
77 super(HooksRegistry, self).register(obj, **kwargs) |
79 super(HooksRegistry, self).register(obj, **kwargs) |
78 |
80 |
79 def call_hooks(self, event, req=None, **kwargs): |
81 def call_hooks(self, event, session=None, **kwargs): |
80 kwargs['event'] = event |
82 kwargs['event'] = event |
81 for hook in sorted(self.possible_objects(req, **kwargs), key=lambda x: x.order): |
83 if session is None: |
82 if hook.enabled: |
84 for hook in sorted(self.possible_objects(session, **kwargs), |
|
85 key=lambda x: x.order): |
83 hook() |
86 hook() |
84 else: |
87 else: |
85 warn('[3.6] %s: enabled is deprecated' % hook.__class__) |
88 # by default, hooks are executed with security turned off |
|
89 with security_enabled(session, read=False): |
|
90 hooks = sorted(self.possible_objects(session, **kwargs), |
|
91 key=lambda x: x.order) |
|
92 with security_enabled(session, write=False): |
|
93 for hook in hooks: |
|
94 hook() |
86 |
95 |
87 VRegistry.REGISTRY_FACTORY['hooks'] = HooksRegistry |
96 VRegistry.REGISTRY_FACTORY['hooks'] = HooksRegistry |
88 |
97 |
89 |
98 |
90 def entity_oldnewvalue(entity, attr): |
99 def entity_oldnewvalue(entity, attr): |
102 |
111 |
103 # some hook specific selectors ################################################# |
112 # some hook specific selectors ################################################# |
104 |
113 |
105 @objectify_selector |
114 @objectify_selector |
106 @lltrace |
115 @lltrace |
|
116 def _bw_is_enabled(cls, req, **kwargs): |
|
117 if cls.enabled: |
|
118 return 1 |
|
119 warn('[3.6] %s: enabled is deprecated' % cls) |
|
120 return 0 |
|
121 |
|
122 @objectify_selector |
|
123 @lltrace |
107 def match_event(cls, req, **kwargs): |
124 def match_event(cls, req, **kwargs): |
108 if kwargs.get('event') in cls.events: |
125 if kwargs.get('event') in cls.events: |
109 return 1 |
126 return 1 |
110 return 0 |
127 return 0 |
111 |
128 |
116 return True # XXX how to deactivate server startup / shutdown event |
133 return True # XXX how to deactivate server startup / shutdown event |
117 return req.is_hook_activated(cls) |
134 return req.is_hook_activated(cls) |
118 |
135 |
119 @objectify_selector |
136 @objectify_selector |
120 @lltrace |
137 @lltrace |
121 def regular_session(cls, req, **kwargs): |
138 def from_dbapi_query(cls, req, **kwargs): |
122 if req is None or req.is_super_session: |
139 if req.running_dbapi_query: |
123 return 0 |
140 return 1 |
124 return 1 |
141 return 0 |
125 |
|
126 |
142 |
127 class rechain(object): |
143 class rechain(object): |
128 def __init__(self, *iterators): |
144 def __init__(self, *iterators): |
129 self.iterators = iterators |
145 self.iterators = iterators |
130 def __iter__(self): |
146 def __iter__(self): |
173 |
189 |
174 # base class for hook ########################################################## |
190 # base class for hook ########################################################## |
175 |
191 |
176 class Hook(AppObject): |
192 class Hook(AppObject): |
177 __registry__ = 'hooks' |
193 __registry__ = 'hooks' |
178 __select__ = match_event() & enabled_category() |
194 __select__ = match_event() & enabled_category() & _bw_is_enabled() |
179 # set this in derivated classes |
195 # set this in derivated classes |
180 events = None |
196 events = None |
181 category = None |
197 category = None |
182 order = 0 |
198 order = 0 |
183 # XXX deprecated |
199 # XXX deprecated |
258 if self.rtype in self.subject_relations: |
274 if self.rtype in self.subject_relations: |
259 meid, seid = self.eidfrom, self.eidto |
275 meid, seid = self.eidfrom, self.eidto |
260 else: |
276 else: |
261 assert self.rtype in self.object_relations |
277 assert self.rtype in self.object_relations |
262 meid, seid = self.eidto, self.eidfrom |
278 meid, seid = self.eidto, self.eidfrom |
263 self._cw.unsafe_execute( |
279 self._cw.execute( |
264 'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'\ |
280 'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'\ |
265 % (self.main_rtype, self.main_rtype, self.main_rtype), |
281 % (self.main_rtype, self.main_rtype, self.main_rtype), |
266 {'x': meid, 'e': seid}, ('x', 'e')) |
282 {'x': meid, 'e': seid}, ('x', 'e')) |
267 |
283 |
268 |
284 |
276 subject_relations = None |
292 subject_relations = None |
277 object_relations = None |
293 object_relations = None |
278 |
294 |
279 def __call__(self): |
295 def __call__(self): |
280 eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0]) |
296 eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0]) |
281 execute = self._cw.unsafe_execute |
297 execute = self._cw.execute |
282 for rel in self.subject_relations: |
298 for rel in self.subject_relations: |
283 if rel in eschema.subjrels: |
299 if rel in eschema.subjrels: |
284 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
300 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
285 'X %s R, NOT R %s P' % (self.rtype, rel, self.rtype), |
301 'X %s R, NOT R %s P' % (self.rtype, rel, self.rtype), |
286 {'x': self.eidfrom, 'p': self.eidto}, 'x') |
302 {'x': self.eidfrom, 'p': self.eidto}, 'x') |
301 subject_relations = None |
317 subject_relations = None |
302 object_relations = None |
318 object_relations = None |
303 |
319 |
304 def __call__(self): |
320 def __call__(self): |
305 eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0]) |
321 eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0]) |
306 execute = self._cw.unsafe_execute |
322 execute = self._cw.execute |
307 for rel in self.subject_relations: |
323 for rel in self.subject_relations: |
308 if rel in eschema.subjrels: |
324 if rel in eschema.subjrels: |
309 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
325 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, ' |
310 'X %s R' % (self.rtype, rel), |
326 'X %s R' % (self.rtype, rel), |
311 {'x': self.eidfrom, 'p': self.eidto}, 'x') |
327 {'x': self.eidfrom, 'p': self.eidto}, 'x') |
505 self.session.vreg.config.sendmails(self.to_send) |
521 self.session.vreg.config.sendmails(self.to_send) |
506 |
522 |
507 |
523 |
508 class RQLPrecommitOperation(Operation): |
524 class RQLPrecommitOperation(Operation): |
509 def precommit_event(self): |
525 def precommit_event(self): |
510 execute = self.session.unsafe_execute |
526 execute = self.session.execute |
511 for rql in self.rqls: |
527 for rql in self.rqls: |
512 execute(*rql) |
528 execute(*rql) |