diff options
Diffstat (limited to 'src/mailman/rest')
| -rw-r--r-- | src/mailman/rest/docs/configuration.txt | 57 | ||||
| -rw-r--r-- | src/mailman/rest/lists.py | 64 |
2 files changed, 119 insertions, 2 deletions
diff --git a/src/mailman/rest/docs/configuration.txt b/src/mailman/rest/docs/configuration.txt index 66502dd15..506e263a2 100644 --- a/src/mailman/rest/docs/configuration.txt +++ b/src/mailman/rest/docs/configuration.txt @@ -4,8 +4,7 @@ Mailing list configuration Mailing lists can be configured via the REST API. - >>> create_list('test-one@example.com') - <mailing list "test-one@example.com" at ...> + >>> mlist = create_list('test-one@example.com') >>> transaction.commit() @@ -180,3 +179,57 @@ Using PATCH, you can change just one attribute. These values are changed permanently. XXX WebOb does not currently support PATCH, so neither does restish. + + +Sub-resources +============= + +Many of the mailing list configuration variables are actually available as +sub-resources on the mailing list. This is because they are collections, +sequences, and other complex configuration types. Their values can be +retrieved and set through the sub-resource. + + +Acceptable aliases +------------------ + +These are recipient aliases that can be used in the To and CC headers instead +of the posting address. They are often used in forwarded emails. By default, +a mailing list has no acceptable aliases. + + >>> dump_json('http://localhost:8001/3.0/lists/' + ... 'test-one@example.com/config/acceptable_aliases') + aliases: [] + http_etag: "c883ba7e4f62819da3c087f086feb5fe524c10b4" + +We can add a few by PUTting them on the sub-resource. The keys in the +dictionary are ignored. + + >>> dump_json('http://localhost:8001/3.0/lists/' + ... 'test-one@example.com/config/acceptable_aliases', + ... dict(one='foo@example.com', + ... two='bar@example.net'), + ... 'PUT') + content-length: 0 + date: ... + server: WSGIServer/... + status: 200 + +The order of aliases is not guaranteed. + + >>> response = call_http( + ... 'http://localhost:8001/3.0/lists/' + ... 'test-one@example.com/config/acceptable_aliases') + >>> for alias in sorted(response['aliases']): + ... print alias + bar@example.net + foo@example.com + +The mailing list has its aliases set. + + >>> from mailman.interfaces.mailinglist import IAcceptableAliasSet + >>> aliases = IAcceptableAliasSet(mlist) + >>> for alias in sorted(aliases.aliases): + ... print alias + bar@example.net + foo@example.com diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py index 6e297d0ed..5b76abbf0 100644 --- a/src/mailman/rest/lists.py +++ b/src/mailman/rest/lists.py @@ -36,6 +36,7 @@ from mailman.config import config from mailman.interfaces.domain import BadDomainSpecificationError from mailman.interfaces.listmanager import ( IListManager, ListAlreadyExistsError) +from mailman.interfaces.mailinglist import IAcceptableAliasSet from mailman.interfaces.member import MemberRole from mailman.rest.helpers import ( CollectionMixin, PATCH, Validator, etag, no_content, path_to, @@ -96,6 +97,19 @@ def config_matcher(request, segments): return None +@restish_matcher +def subresource_config_matcher(request, segments): + """A matcher for configuration sub-resources. + + e.g. /config/acceptable_aliases + """ + if len(segments) != 2 or segments[0] != 'config': + return None + # Don't check here whether it's a known subresource or not. Let that be + # done in subresource_config() method below. + return (), dict(attribute=segments[1]), () + + class _ListBase(resource.Resource, CollectionMixin): """Shared base class for mailing list representations.""" @@ -154,6 +168,19 @@ class AList(_ListBase): """Return a mailing list configuration object.""" return ListConfiguration(self._mlist) + @resource.child(subresource_config_matcher) + def subresource_config(self, request, segments, attribute): + """Return the subresource configuration object. + + This will return a Bad Request if it isn't a known subresource. + """ + missing = object() + subresource_class = SUBRESOURCES.get(attribute, missing) + if subresource_class is missing: + return http.bad_request( + [], 'Unknown attribute {0}'.format(attribute)) + return subresource_class(self._mlist, attribute) + class AllLists(_ListBase): @@ -281,3 +308,40 @@ class ListConfiguration(resource.Resource): except ValueError as error: return http.bad_request([], str(error)) return http.ok([], '') + + + +class AcceptableAliases(resource.Resource): + """Resource for the acceptable aliases of a mailing list.""" + + def __init__(self, mailing_list, attribute): + assert attribute == 'acceptable_aliases', ( + 'unexpected attribute: {0}'.format(attribute)) + self._mlist = mailing_list + + @resource.GET() + def aliases(self, request): + """Return the mailing list's acceptable aliases.""" + aliases = IAcceptableAliasSet(self._mlist) + resource = dict(aliases=list(aliases.aliases)) + return http.ok([], etag(resource)) + + @resource.PUT() + def put_configuration(self, request): + """Change the acceptable aliases. + + Because this is a PUT operation, all previous aliases are cleared + first. Thus, this is an overwrite. The keys in the request are + ignored. + """ + aliases = IAcceptableAliasSet(self._mlist) + aliases.clear() + for alias in request.POST.values(): + aliases.add(unicode(alias)) + return http.ok([], '') + + + +SUBRESOURCES = dict( + acceptable_aliases=AcceptableAliases, + ) |
