--- a/src/pyams_utils/property.py Wed Jul 12 13:55:47 2017 +0200
+++ b/src/pyams_utils/property.py Wed Jul 12 13:56:41 2017 +0200
@@ -18,8 +18,6 @@
# import interfaces
# import packages
-from pyams_utils.request import check_request, get_request_data, set_request_data
-from pyams_utils.session import get_session_data, set_session_data
from zope.schema.fieldproperty import FieldProperty
@@ -75,73 +73,6 @@
return result
-_marker = object()
-
-
-def request_property(key, prefix=None):
- """Define a method decorator used to store result into current request's annotations
-
- If not 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: session's 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)
- if not key:
- key = '{1}::{0!r}'.format(obj, prefix or func.__name__)
- 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: wrapper(x, key=key)
-
- return request_decorator
-
-
-def session_property(app, key=None, prefix=None):
- """Define a method decorator used to store result into request's session
-
- If no request is currently running, a new one is created.
-
- :param str app: application identifier used to prefix session keys
- :param str key: session's value key; if *None*, the key will be the method's object; if *key* is a callable
- object, il 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 session_decorator(func):
-
- def wrapper(obj, app, key, *args, **kwargs):
- request = check_request()
- if callable(key):
- key = key(obj)
- if not key:
- key = '{1}::{0!r}'.format(obj, prefix or func.__name__)
- data = get_session_data(request, app, key, _marker)
- if data is _marker:
- data = func
- if callable(data):
- data = data(obj, *args, **kwargs)
- set_session_data(request, app, key, data)
- return data
-
- return lambda x: wrapper(x, app=app, key=key)
-
- return session_decorator
-
-
class classproperty:
"""Same decorator as property(), but passes obj.__class__ instead of obj to fget/fset/fdel.
--- 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
--- a/src/pyams_utils/session.py Wed Jul 12 13:55:47 2017 +0200
+++ b/src/pyams_utils/session.py Wed Jul 12 13:56:41 2017 +0200
@@ -18,6 +18,42 @@
# import interfaces
# import packages
+from pyams_utils.request import check_request
+
+
+_marker = object()
+
+
+def session_property(app, key=None, prefix=None):
+ """Define a method decorator used to store result into request's session
+
+ If no request is currently running, a new one is created.
+
+ :param str app: application identifier used to prefix session keys
+ :param str key: session's value key; if *None*, the key will be the method's object; if *key* is a callable
+ object, il 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 session_decorator(func):
+
+ def wrapper(obj, app, key, *args, **kwargs):
+ request = check_request()
+ if callable(key):
+ key = key(obj, *args, **kwargs)
+ if not key:
+ key = '{1}::{0!r}'.format(obj, prefix or func.__name__)
+ data = get_session_data(request, app, key, _marker)
+ if data is _marker:
+ data = func
+ if callable(data):
+ data = data(obj, *args, **kwargs)
+ set_session_data(request, app, key, data)
+ return data
+
+ return lambda x, *args, **kwargs: wrapper(x, app, key, *args, **kwargs)
+
+ return session_decorator
def get_session_data(request, app, key, default=None):
--- a/src/pyams_utils/zodb.py Wed Jul 12 13:55:47 2017 +0200
+++ b/src/pyams_utils/zodb.py Wed Jul 12 13:56:41 2017 +0200
@@ -17,6 +17,7 @@
# import interfaces
from persistent.interfaces import IPersistent
+from pyams_utils.interfaces import ICacheKeyValue
from pyams_utils.interfaces.site import IOptionalUtility
from pyams_utils.interfaces.zeo import IZEOConnection
from transaction.interfaces import ITransactionManager
@@ -71,6 +72,11 @@
# recent spelling.
+@adapter_config(context=object, provides=ICacheKeyValue)
+def persistent_key_adapter(obj):
+ return '{0!r}'.format(obj)
+
+
@implementer(IZEOConnection)
class ZEOConnection(object):
"""ZEO connection object