summaryrefslogtreecommitdiff
path: root/src/mailman/rest
diff options
context:
space:
mode:
authorBarry Warsaw2016-06-28 06:36:02 -0400
committerBarry Warsaw2016-06-28 06:36:02 -0400
commit0265a93b24f2061d765d8f3eb0fc27c9fd080510 (patch)
tree996cf5051ddd0144cea90336bbde6ef7c6ef700a /src/mailman/rest
parentc71417b39bc9832b71f766e525a08addda6166cd (diff)
downloadmailman-0265a93b24f2061d765d8f3eb0fc27c9fd080510.tar.gz
mailman-0265a93b24f2061d765d8f3eb0fc27c9fd080510.tar.zst
mailman-0265a93b24f2061d765d8f3eb0fc27c9fd080510.zip
Better handling of the REST API plumbing.
* Add a version_info field which is a better way to do ordered comparisions of the API version. * All subresources now get their .api attribute set automatically, if they are passed back through the ObjectRouter. No more fiddling with context['api'] (unless of course, they don't make a roundtrip through the main ObjectRouter loop.
Diffstat (limited to 'src/mailman/rest')
-rw-r--r--src/mailman/rest/members.py4
-rw-r--r--src/mailman/rest/root.py4
-rw-r--r--src/mailman/rest/users.py24
-rw-r--r--src/mailman/rest/wsgiapp.py11
4 files changed, 25 insertions, 18 deletions
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index b6158dd3c..9ed12d98b 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -123,7 +123,7 @@ class AMember(_MemberBase):
return NotFound(), []
if self._member is None:
return NotFound(), []
- member_id = context['api'].from_uuid(self._member_id)
+ member_id = self.api.from_uuid(self._member_id)
child = Preferences(
self._member.preferences, 'members/{}'.format(member_id))
return child, []
@@ -135,7 +135,7 @@ class AMember(_MemberBase):
return NotFound(), []
if self._member is None:
return NotFound(), []
- member_id = context['api'].from_uuid(self._member_id)
+ member_id = self.api.from_uuid(self._member_id)
child = ReadOnlyPreferences(
self._member, 'members/{}/all'.format(member_id))
return child, []
diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py
index 3c38ded5d..ff459bbcb 100644
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -220,7 +220,7 @@ class TopLevel:
resource = FindMembers()
else:
try:
- member_id = context['api'].to_uuid(segment)
+ member_id = self.api.to_uuid(segment)
except ValueError:
member_id = None
resource = AMember(member_id)
@@ -233,7 +233,7 @@ class TopLevel:
return AllUsers()
else:
user_identifier = segments.pop(0)
- return AUser(context['api'], user_identifier), segments
+ return AUser(user_identifier), segments
@child()
def owners(self, context, segments):
diff --git a/src/mailman/rest/users.py b/src/mailman/rest/users.py
index dfef466ca..ede435ad8 100644
--- a/src/mailman/rest/users.py
+++ b/src/mailman/rest/users.py
@@ -17,6 +17,7 @@
"""REST for users."""
+from functools import lru_cache
from lazr.config import as_boolean
from mailman import public
from mailman.config import config
@@ -168,11 +169,9 @@ class AllUsers(_UserBase):
class AUser(_UserBase):
"""A user."""
- def __init__(self, api, user_identifier):
+ def __init__(self, user_identifier):
"""Get a user by various type of identifiers.
- :param api: The REST API object.
- :type api: IAPI
:param user_identifier: The identifier used to retrieve the user. The
identifier may either be an email address controlled by the user
or the UUID of the user. The type of identifier is auto-detected
@@ -181,19 +180,26 @@ class AUser(_UserBase):
API 3.0 are integers, while in 3.1 are hex.
:type user_identifier: string
"""
- self.api = api
+ self._user_identifier = user_identifier
+ # Defer calculation of the user until the API object is set, since
+ # that will determine how to interpret the user identifier. For ease
+ # of code migration, use an _user caching property (see below).
+
+ @property
+ @lru_cache(1)
+ def _user(self):
user_manager = getUtility(IUserManager)
- if '@' in user_identifier:
- self._user = user_manager.get_user(user_identifier)
+ if '@' in self._user_identifier:
+ return user_manager.get_user(self._user_identifier)
else:
# The identifier is the string representation of a UUID, either an
# int in API 3.0 or a hex in API 3.1.
try:
- user_id = api.to_uuid(user_identifier)
+ user_id = self.api.to_uuid(self._user_identifier)
except ValueError:
- self._user = None
+ return None
else:
- self._user = user_manager.get_user_by_id(user_id)
+ return user_manager.get_user_by_id(user_id)
def on_get(self, request, response):
"""Return a single user end-point."""
diff --git a/src/mailman/rest/wsgiapp.py b/src/mailman/rest/wsgiapp.py
index 67f920205..0aedff839 100644
--- a/src/mailman/rest/wsgiapp.py
+++ b/src/mailman/rest/wsgiapp.py
@@ -83,11 +83,6 @@ class Middleware:
performed.
"""
def process_resource(self, request, response, resource, params):
- # Set this attribute on the resource right before it is dispatched to.
- # This can be used by the resource to provide different responses
- # based on the API version, and for path_to() to provide an API
- # version-specific path.
- resource.api = params.pop('api')
# Check the authorization credentials.
authorized = False
if request.auth is not None and request.auth.startswith('Basic '):
@@ -122,6 +117,8 @@ class ObjectRouter:
resource = self._root
context = {}
while True:
+ # Plumb the API through to all child resources.
+ api = getattr(resource, 'api', None)
# See if any of the resource's child links match the next segment.
for name in dir(resource):
if name.startswith('__') and name.endswith('__'):
@@ -172,6 +169,10 @@ class ObjectRouter:
resource, segments = result
else:
resource = result
+ # See if the context set an API and set it on the next
+ # resource in the chain, falling back to the parent resource's
+ # API if there is one.
+ resource.api = context.pop('api', api)
# The method could have truncated the remaining segments,
# meaning, it's consumed all the path segments, or this is the
# last path segment. In that case the resource we're left at