107 """ |
107 """ |
108 def __init__(self, cnx, mode, *categories): |
108 def __init__(self, cnx, mode, *categories): |
109 assert mode in (HOOKS_ALLOW_ALL, HOOKS_DENY_ALL) |
109 assert mode in (HOOKS_ALLOW_ALL, HOOKS_DENY_ALL) |
110 self.cnx = cnx |
110 self.cnx = cnx |
111 self.mode = mode |
111 self.mode = mode |
112 self.categories = categories |
112 self.categories = set(categories) |
113 self.oldmode = None |
113 self.old_mode = None |
114 self.changes = () |
114 self.old_categories = None |
115 |
115 |
116 def __enter__(self): |
116 def __enter__(self): |
117 self.oldmode = self.cnx.hooks_mode |
117 self.old_mode = self.cnx._hooks_mode |
118 self.cnx.hooks_mode = self.mode |
118 self.old_categories = self.cnx._hooks_categories |
119 if self.mode is HOOKS_DENY_ALL: |
119 self.cnx._hooks_mode = self.mode |
120 self.changes = self.cnx.enable_hook_categories(*self.categories) |
120 self.cnx._hooks_categories = self.categories |
121 else: |
|
122 self.changes = self.cnx.disable_hook_categories(*self.categories) |
|
123 |
121 |
124 def __exit__(self, exctype, exc, traceback): |
122 def __exit__(self, exctype, exc, traceback): |
125 try: |
123 self.cnx._hooks_mode = self.old_mode |
126 if self.categories: |
124 self.cnx._hooks_categories = self.old_categories |
127 if self.mode is HOOKS_DENY_ALL: |
|
128 self.cnx.disable_hook_categories(*self.categories) |
|
129 else: |
|
130 self.cnx.enable_hook_categories(*self.categories) |
|
131 finally: |
|
132 self.cnx.hooks_mode = self.oldmode |
|
133 |
125 |
134 |
126 |
135 @deprecated('[3.17] use <object>.security_enabled instead') |
127 @deprecated('[3.17] use <object>.security_enabled instead') |
136 def security_enabled(obj, *args, **kwargs): |
128 def security_enabled(obj, *args, **kwargs): |
137 return obj.security_enabled(*args, **kwargs) |
129 return obj.security_enabled(*args, **kwargs) |
236 'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error |
228 'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error |
237 has been raised during the transaction and so it must be rolled back). |
229 has been raised during the transaction and so it must be rolled back). |
238 |
230 |
239 Hooks controls: |
231 Hooks controls: |
240 |
232 |
241 :attr:`hooks_mode`, may be either `HOOKS_ALLOW_ALL` or `HOOKS_DENY_ALL`. |
233 .. automethod:: cubicweb.server.session.Connection.deny_all_hooks_but |
242 |
234 .. automethod:: cubicweb.server.session.Connection.allow_all_hooks_but |
243 :attr:`enabled_hook_cats`, when :attr:`hooks_mode` is |
|
244 `HOOKS_DENY_ALL`, this set contains hooks categories that are enabled. |
|
245 |
|
246 :attr:`disabled_hook_cats`, when :attr:`hooks_mode` is |
|
247 `HOOKS_ALLOW_ALL`, this set contains hooks categories that are disabled. |
|
248 |
235 |
249 Security level Management: |
236 Security level Management: |
250 |
237 |
251 :attr:`read_security` and :attr:`write_security`, boolean flags telling if |
238 :attr:`read_security` and :attr:`write_security`, boolean flags telling if |
252 read/write security is currently activated. |
239 read/write security is currently activated. |
281 self.pending_operations = [] |
268 self.pending_operations = [] |
282 #: (None, 'precommit', 'postcommit', 'uncommitable') |
269 #: (None, 'precommit', 'postcommit', 'uncommitable') |
283 self.commit_state = None |
270 self.commit_state = None |
284 |
271 |
285 # hook control attribute |
272 # hook control attribute |
286 self.hooks_mode = HOOKS_ALLOW_ALL |
273 # `_hooks_mode`, may be either `HOOKS_ALLOW_ALL` or `HOOKS_DENY_ALL`. |
287 self.disabled_hook_cats = set() |
274 self._hooks_mode = HOOKS_ALLOW_ALL |
288 self.enabled_hook_cats = set() |
275 # `_hooks_categories`, when :attr:`_hooks_mode` is `HOOKS_DENY_ALL`, |
|
276 # this set contains hooks categories that are enabled ; |
|
277 # when :attr:`_hooks_mode` is `HOOKS_ALLOW_ALL`, it contains hooks |
|
278 # categories that are disabled. |
|
279 self._hooks_categories = set() |
289 self.pruned_hooks_cache = {} |
280 self.pruned_hooks_cache = {} |
290 |
281 |
291 # security control attributes |
282 # security control attributes |
292 self._read_security = DEFAULT_SECURITY # handled by a property |
283 self._read_security = DEFAULT_SECURITY # handled by a property |
293 self.write_security = DEFAULT_SECURITY |
284 self.write_security = DEFAULT_SECURITY |
672 |
663 |
673 # Hooks control ########################################################### |
664 # Hooks control ########################################################### |
674 |
665 |
675 @_open_only |
666 @_open_only |
676 def allow_all_hooks_but(self, *categories): |
667 def allow_all_hooks_but(self, *categories): |
|
668 """Context manager to enable all hooks but those in the given |
|
669 categories. |
|
670 """ |
677 return _hooks_control(self, HOOKS_ALLOW_ALL, *categories) |
671 return _hooks_control(self, HOOKS_ALLOW_ALL, *categories) |
678 |
672 |
679 @_open_only |
673 @_open_only |
680 def deny_all_hooks_but(self, *categories): |
674 def deny_all_hooks_but(self, *categories): |
|
675 """Context manager to disable all hooks but those in the given |
|
676 categories. |
|
677 """ |
681 return _hooks_control(self, HOOKS_DENY_ALL, *categories) |
678 return _hooks_control(self, HOOKS_DENY_ALL, *categories) |
682 |
|
683 @_open_only |
|
684 def disable_hook_categories(self, *categories): |
|
685 """disable the given hook categories: |
|
686 |
|
687 - on HOOKS_DENY_ALL mode, ensure those categories are not enabled |
|
688 - on HOOKS_ALLOW_ALL mode, ensure those categories are disabled |
|
689 """ |
|
690 changes = set() |
|
691 self.pruned_hooks_cache.clear() |
|
692 categories = set(categories) |
|
693 if self.hooks_mode is HOOKS_DENY_ALL: |
|
694 enabledcats = self.enabled_hook_cats |
|
695 changes = enabledcats & categories |
|
696 enabledcats -= changes # changes is small hence faster |
|
697 else: |
|
698 disabledcats = self.disabled_hook_cats |
|
699 changes = categories - disabledcats |
|
700 disabledcats |= changes # changes is small hence faster |
|
701 return tuple(changes) |
|
702 |
|
703 @_open_only |
|
704 def enable_hook_categories(self, *categories): |
|
705 """enable the given hook categories: |
|
706 |
|
707 - on HOOKS_DENY_ALL mode, ensure those categories are enabled |
|
708 - on HOOKS_ALLOW_ALL mode, ensure those categories are not disabled |
|
709 """ |
|
710 changes = set() |
|
711 self.pruned_hooks_cache.clear() |
|
712 categories = set(categories) |
|
713 if self.hooks_mode is HOOKS_DENY_ALL: |
|
714 enabledcats = self.enabled_hook_cats |
|
715 changes = categories - enabledcats |
|
716 enabledcats |= changes # changes is small hence faster |
|
717 else: |
|
718 disabledcats = self.disabled_hook_cats |
|
719 changes = disabledcats & categories |
|
720 disabledcats -= changes # changes is small hence faster |
|
721 return tuple(changes) |
|
722 |
679 |
723 @_open_only |
680 @_open_only |
724 def is_hook_category_activated(self, category): |
681 def is_hook_category_activated(self, category): |
725 """return a boolean telling if the given category is currently activated |
682 """return a boolean telling if the given category is currently activated |
726 or not |
683 or not |
727 """ |
684 """ |
728 if self.hooks_mode is HOOKS_DENY_ALL: |
685 if self._hooks_mode is HOOKS_DENY_ALL: |
729 return category in self.enabled_hook_cats |
686 return category in self._hooks_categories |
730 return category not in self.disabled_hook_cats |
687 return category not in self._hooks_categories |
731 |
688 |
732 @_open_only |
689 @_open_only |
733 def is_hook_activated(self, hook): |
690 def is_hook_activated(self, hook): |
734 """return a boolean telling if the given hook class is currently |
691 """return a boolean telling if the given hook class is currently |
735 activated or not |
692 activated or not |