diff options
Diffstat (limited to 'src/mailman/rest/lists.py')
| -rw-r--r-- | src/mailman/rest/lists.py | 127 |
1 files changed, 66 insertions, 61 deletions
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py index 552824927..580b6e898 100644 --- a/src/mailman/rest/lists.py +++ b/src/mailman/rest/lists.py @@ -26,32 +26,33 @@ __all__ = [ 'ListArchivers', 'ListConfiguration', 'ListsForDomain', + 'Styles', ] from lazr.config import as_boolean from operator import attrgetter -from restish import http, resource from zope.component import getUtility from mailman.app.lifecycle import create_list, remove_list +from mailman.config import config from mailman.interfaces.domain import BadDomainSpecificationError from mailman.interfaces.listmanager import ( IListManager, ListAlreadyExistsError) from mailman.interfaces.mailinglist import IListArchiverSet from mailman.interfaces.member import MemberRole +from mailman.interfaces.styles import IStyleManager from mailman.interfaces.subscriptions import ISubscriptionService from mailman.rest.configuration import ListConfiguration from mailman.rest.helpers import ( - CollectionMixin, GetterSetter, PATCH, etag, no_content, paginate, path_to, - restish_matcher) + CollectionMixin, GetterSetter, NotFound, bad_request, child, created, + etag, no_content, not_found, okay, paginate, path_to) from mailman.rest.members import AMember, MemberCollection from mailman.rest.moderation import HeldMessages, SubscriptionRequests from mailman.rest.validator import Validator -@restish_matcher def member_matcher(request, segments): """A matcher of member URLs inside mailing lists. @@ -64,13 +65,9 @@ def member_matcher(request, segments): except KeyError: # Not a valid role. return None - # No more segments. - # XXX 2010-02-25 barry Matchers are undocumented in restish; they return a - # 3-tuple of (match_args, match_kws, segments). return (), dict(role=role, email=segments[1]), () -@restish_matcher def roster_matcher(request, segments): """A matcher of all members URLs inside mailing lists. @@ -85,7 +82,6 @@ def roster_matcher(request, segments): return None -@restish_matcher def config_matcher(request, segments): """A matcher for a mailing list's configuration resource. @@ -103,7 +99,7 @@ def config_matcher(request, segments): -class _ListBase(resource.Resource, CollectionMixin): +class _ListBase(CollectionMixin): """Shared base class for mailing list representations.""" def _resource_as_dict(self, mlist): @@ -138,66 +134,66 @@ class AList(_ListBase): else: self._mlist = manager.get_by_list_id(list_identifier) - @resource.GET() - def mailing_list(self, request): + def on_get(self, request, response): """Return a single mailing list end-point.""" if self._mlist is None: - return http.not_found() - return http.ok([], self._resource_as_json(self._mlist)) + not_found(response) + else: + okay(response, self._resource_as_json(self._mlist)) - @resource.DELETE() - def delete_list(self, request): + def on_delete(self, request, response): """Delete the named mailing list.""" if self._mlist is None: - return http.not_found() - remove_list(self._mlist) - return no_content() + not_found(response) + else: + remove_list(self._mlist) + no_content(response) - @resource.child(member_matcher) + @child(member_matcher) def member(self, request, segments, role, email): """Return a single member representation.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] members = getUtility(ISubscriptionService).find_members( email, self._mlist.list_id, role) if len(members) == 0: - return http.not_found() + return NotFound(), [] assert len(members) == 1, 'Too many matches' return AMember(members[0].member_id) - @resource.child(roster_matcher) + @child(roster_matcher) def roster(self, request, segments, role): """Return the collection of all a mailing list's members.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] return MembersOfList(self._mlist, role) - @resource.child(config_matcher) + @child(config_matcher) def config(self, request, segments, attribute=None): """Return a mailing list configuration object.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] return ListConfiguration(self._mlist, attribute) - @resource.child() + @child() def held(self, request, segments): """Return a list of held messages for the mailing list.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] return HeldMessages(self._mlist) - @resource.child() + @child() def requests(self, request, segments): """Return a list of subscription/unsubscription requests.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] return SubscriptionRequests(self._mlist) - @resource.child() + @child() def archivers(self, request, segments): """Return a representation of mailing list archivers.""" if self._mlist is None: - return http.not_found() + return NotFound(), [] return ListArchivers(self._mlist) @@ -205,8 +201,7 @@ class AList(_ListBase): class AllLists(_ListBase): """The mailing lists.""" - @resource.POST() - def create(self, request): + def on_post(self, request, response): """Create a new mailing list.""" try: validator = Validator(fqdn_listname=unicode, @@ -214,22 +209,20 @@ class AllLists(_ListBase): _optional=('style_name',)) mlist = create_list(**validator(request)) except ListAlreadyExistsError: - return http.bad_request([], b'Mailing list exists') + bad_request(response, b'Mailing list exists') except BadDomainSpecificationError as error: - return http.bad_request([], b'Domain does not exist: {0}'.format( - error.domain)) + bad_request( + response, + b'Domain does not exist: {0}'.format(error.domain)) except ValueError as error: - return http.bad_request([], str(error)) - # wsgiref wants headers to be bytes, not unicodes. - location = path_to('lists/{0}'.format(mlist.list_id)) - # Include no extra headers or body. - return http.created(location, [], None) + bad_request(response, str(error)) + else: + created(response, path_to('lists/{0}'.format(mlist.list_id))) - @resource.GET() - def collection(self, request): + def on_get(self, request, response): """/lists""" resource = self._make_collection(request) - return http.ok([], etag(resource)) + okay(response, etag(resource)) @@ -257,11 +250,10 @@ class ListsForDomain(_ListBase): def __init__(self, domain): self._domain = domain - @resource.GET() - def collection(self, request): + def on_get(self, request, response): """/domains/<domain>/lists""" resource = self._make_collection(request) - return http.ok([], etag(resource)) + okay(response, etag(resource)) @paginate def _get_collection(self, request): @@ -287,21 +279,20 @@ class ArchiverGetterSetter(GetterSetter): archiver.is_enabled = as_boolean(value) -class ListArchivers(resource.Resource): +class ListArchivers: """The archivers for a list, with their enabled flags.""" def __init__(self, mlist): self._mlist = mlist - @resource.GET() - def statuses(self, request): + def on_get(self, request, response): """Get all the archiver statuses.""" archiver_set = IListArchiverSet(self._mlist) resource = {archiver.name: archiver.is_enabled for archiver in archiver_set.archivers} - return http.ok([], etag(resource)) + okay(response, etag(resource)) - def patch_put(self, request, is_optional): + def patch_put(self, request, response, is_optional): archiver_set = IListArchiverSet(self._mlist) kws = {archiver.name: ArchiverGetterSetter(self._mlist) for archiver in archiver_set.archivers} @@ -311,15 +302,29 @@ class ListArchivers(resource.Resource): try: Validator(**kws).update(self._mlist, request) except ValueError as error: - return http.bad_request([], str(error)) - return no_content() + bad_request(response, str(error)) + else: + no_content(response) - @resource.PUT() - def put_statuses(self, request): + def on_put(self, request, response): """Update all the archiver statuses.""" - return self.patch_put(request, is_optional=False) + self.patch_put(request, response, is_optional=False) - @PATCH() - def patch_statuses(self, request): + def on_patch(self, request, response): """Patch some archiver statueses.""" - return self.patch_put(request, is_optional=True) + self.patch_put(request, response, is_optional=True) + + + +class Styles: + """Simple resource representing all list styles.""" + + def __init__(self): + manager = getUtility(IStyleManager) + style_names = sorted(style.name for style in manager.styles) + self._resource = dict( + style_names=style_names, + default=config.styles.default) + + def on_get(self, request, response): + okay(response, etag(self._resource)) |
