From 8b2457f93da45778edc371d46eed40f7c8ecda7e Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 2 Apr 2016 23:06:16 -0400 Subject: Checkpointing. --- setup.py | 2 +- src/mailman/rest/lists.py | 6 +- src/mailman/rest/root.py | 81 ++++++++---------------- src/mailman/rest/users.py | 21 +++---- src/mailman/rest/wsgiapp.py | 148 +++++++++++++++++++++++++++----------------- 5 files changed, 131 insertions(+), 127 deletions(-) diff --git a/setup.py b/setup.py index 4a2b178df..94d56af43 100644 --- a/setup.py +++ b/setup.py @@ -105,7 +105,7 @@ case second `m'. Any other spelling is incorrect.""", }, install_requires = [ 'alembic', - 'falcon>=0.3rc1,<1.0', + 'falcon>=0.3rc1', 'flufl.bounce', 'flufl.i18n', 'flufl.lock', diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py index 7315d805a..417db4839 100644 --- a/src/mailman/rest/lists.py +++ b/src/mailman/rest/lists.py @@ -43,7 +43,7 @@ from mailman.rest.validator import Validator from zope.component import getUtility -def member_matcher(request, segments): +def member_matcher(segments): """A matcher of member URLs inside mailing lists. e.g. //aperson@example.org @@ -58,7 +58,7 @@ def member_matcher(request, segments): return (), dict(role=role, email=segments[1]), () -def roster_matcher(request, segments): +def roster_matcher(segments): """A matcher of all members URLs inside mailing lists. e.g. /roster/ @@ -72,7 +72,7 @@ def roster_matcher(request, segments): return None -def config_matcher(request, segments): +def config_matcher(segments): """A matcher for a mailing list's configuration resource. e.g. /config diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py index 366dc3d08..c07be5388 100644 --- a/src/mailman/rest/root.py +++ b/src/mailman/rest/root.py @@ -17,9 +17,6 @@ """The root of the REST API.""" -import falcon - -from base64 import b64decode from mailman import public from mailman.config import config from mailman.core.api import API30, API31 @@ -55,48 +52,24 @@ class Root: """ @child('3.0') - def api_version_30(self, request, segments): + def api_version_30(self, context, segments): # API version 3.0 was introduced in Mailman 3.0. - request.context['api'] = API30 - return self._check_authorization(request, segments) + context['api'] = API30 + return TopLevel() @child('3.1') - def api_version_31(self, request, segments): + def api_version_31(self, context, segments): # API version 3.1 was introduced in Mailman 3.1. Primary backward # incompatible difference is that uuids are represented as hex strings # instead of 128 bit integers. The latter is not compatible with all # versions of JavaScript. - request.context['api'] = API31 - return self._check_authorization(request, segments) - - def _check_authorization(self, request, segments): - # We have to do this here instead of in a @falcon.before() handler - # because those handlers are not compatible with our custom traversal - # logic. Specifically, falcon's before/after handlers will call the - # responder, but the method we're wrapping isn't a responder, it's a - # child traversal method. There's no way to cause the thing that - # calls the before hook to follow through with the child traversal in - # the case where no error is raised. - if request.auth is None: - raise falcon.HTTPUnauthorized( - '401 Unauthorized', - 'The REST API requires authentication') - if request.auth.startswith('Basic '): - # b64decode() returns bytes, but we require a str. - credentials = b64decode(request.auth[6:]).decode('utf-8') - username, password = credentials.split(':', 1) - if (username != config.webservice.admin_user or - password != config.webservice.admin_pass): - # Not authorized. - raise falcon.HTTPUnauthorized( - '401 Unauthorized', - 'User is not authorized for the REST API') + context['api'] = API31 return TopLevel() @public class Versions: - def on_get(self, request, response): + def on_get(self, context, response): """//system/versions""" resource = dict( mailman_version=system.mailman_version, @@ -112,7 +85,7 @@ class SystemConfiguration: def __init__(self, section=None): self._section = section - def on_get(self, request, response): + def on_get(self, context, response): if self._section is None: resource = dict( sections=sorted(section.name for section in config)) @@ -131,14 +104,14 @@ class SystemConfiguration: @public class Pipelines: - def on_get(self, request, response): + def on_get(self, context, response): resource = dict(pipelines=sorted(config.pipelines)) okay(response, etag(resource)) @public class Chains: - def on_get(self, request, response): + def on_get(self, context, response): resource = dict(chains=sorted(config.chains)) okay(response, etag(resource)) @@ -155,7 +128,7 @@ class Reserved: def __init__(self, segments): self._resource_path = SLASH.join(segments) - def on_delete(self, request, response): + def on_delete(self, context, response): if self._resource_path != 'uids/orphans': not_found(response) return @@ -168,7 +141,7 @@ class TopLevel: """Top level collections and entries.""" @child() - def system(self, request, segments): + def system(self, context, segments): """//system""" if len(segments) == 0: # This provides backward compatibility; see /system/versions. @@ -197,22 +170,22 @@ class TopLevel: return NotFound(), [] @child() - def addresses(self, request, segments): + def addresses(self, context, segments): """//addresses //addresses/ """ if len(segments) == 0: resource = AllAddresses() - resource.api = request.context['api'] + resource.api = context['api'] return resource else: email = segments.pop(0) resource = AnAddress(email) - resource.api = request.context['api'] + resource.api = context['api'] return resource, segments @child() - def domains(self, request, segments): + def domains(self, context, segments): """//domains //domains/ """ @@ -223,7 +196,7 @@ class TopLevel: return ADomain(domain), segments @child() - def lists(self, request, segments): + def lists(self, context, segments): """//lists //lists/styles //lists/ @@ -240,9 +213,9 @@ class TopLevel: return AList(list_identifier), segments @child() - def members(self, request, segments): + def members(self, context, segments): """//members""" - api = request.context['api'] + api = context['api'] if len(segments) == 0: resource = AllMembers() resource.api = api @@ -258,9 +231,9 @@ class TopLevel: return resource, segments @child() - def users(self, request, segments): + def users(self, context, segments): """//users""" - api = request.context['api'] + api = context['api'] if len(segments) == 0: resource = AllUsers() resource.api = api @@ -270,17 +243,17 @@ class TopLevel: return AUser(api, user_id), segments @child() - def owners(self, request, segments): + def owners(self, context, segments): """//owners""" if len(segments) != 0: return BadRequest(), [] else: resource = ServerOwners() - resource.api = request.context['api'] + resource.api = context['api'] return resource, segments @child() - def templates(self, request, segments): + def templates(self, context, segments): """//templates//