--- a/src/pyams_utils/request.py Wed Jul 12 13:55:47 2017 +0200
+++ b/src/pyams_utils/request.py Wed Jul 12 13:56:41 2017 +0200
@@ -16,15 +16,82 @@
# import standard library
# import interfaces
-from pyams_utils.interfaces import MissingRequestError
+from pyams_utils.interfaces import MissingRequestError, ICacheKeyValue
+from pyramid.interfaces import IAuthenticationPolicy, IAuthorizationPolicy
from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
# import packages
from pyramid.request import Request
+from pyramid.security import Allowed
from pyramid.threadlocal import get_current_request, get_current_registry
from zope.interface import alsoProvides
+_marker = object()
+
+
+def request_property(key=None, prefix=None):
+ """Define a method decorator used to store result into current request's annotations
+
+ If no request is currently running, a new one is created.
+ `key` is a required argument; if None, the key will be the method's object
+
+ :param str key: annotations value key; if *None*, the key will be the method's object; if *key* is a callable
+ object, it will be called to get the actual session key
+ :param prefix: str; prefix to use for session key; if *None*, the prefix will be the property name
+ """
+
+ def request_decorator(func):
+
+ def wrapper(obj, key, *args, **kwargs):
+ request = check_request()
+ if callable(key):
+ key = key(obj, *args, **kwargs)
+ if not key:
+ key = '{0}::{1}'.format(prefix or func.__name__, ICacheKeyValue(obj))
+ if args:
+ key += '::' + '::'.join((ICacheKeyValue(arg) for arg in args))
+ if kwargs:
+ key += '::' + '::'.join((ICacheKeyValue(arg) for arg in kwargs.items()))
+ data = get_request_data(request, key, _marker)
+ if data is _marker:
+ data = func
+ if callable(data):
+ data = data(obj, *args, **kwargs)
+ set_request_data(request, key, data)
+ return data
+
+ return lambda x, *args, **kwargs: wrapper(x, key, *args, **kwargs)
+
+ return request_decorator
+
+
+class PyAMSRequest(Request):
+ """Custom request factory
+
+ Used to add 'context' argument to 'effective_principals' method call
+ to be able to get 'roles' principals
+ """
+
+ @request_property(key=None)
+ def has_permission(self, permission, context=None):
+ if context is None:
+ context = self.context
+ try:
+ reg = self.registry
+ except AttributeError:
+ reg = get_current_registry()
+ authn_policy = reg.queryUtility(IAuthenticationPolicy)
+ if authn_policy is None:
+ return Allowed('No authentication policy in use.')
+ authz_policy = reg.queryUtility(IAuthorizationPolicy)
+ if authz_policy is None:
+ raise ValueError('Authentication policy registered without '
+ 'authorization policy') # should never happen
+ principals = authn_policy.effective_principals(self, context)
+ return authz_policy.permits(context, principals, permission)
+
+
def get_request(raise_exception=True):
"""Get current request