summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2010-02-25 20:38:25 -0500
committerBarry Warsaw2010-02-25 20:38:25 -0500
commitb2ae2b7795719f17cb2b6c7ed14e5b4c7c8eae47 (patch)
tree40233249ecb3c71f834cb5db7e33b9e56c3b1b4f /src
parentea7bb1a31c51a59949310c9837020908476e2c0d (diff)
downloadmailman-b2ae2b7795719f17cb2b6c7ed14e5b4c7c8eae47.tar.gz
mailman-b2ae2b7795719f17cb2b6c7ed14e5b4c7c8eae47.tar.zst
mailman-b2ae2b7795719f17cb2b6c7ed14e5b4c7c8eae47.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/rest/docs/lists.txt6
-rw-r--r--src/mailman/rest/docs/membership.txt33
-rw-r--r--src/mailman/rest/domains.py8
-rw-r--r--src/mailman/rest/lists.py140
-rw-r--r--src/mailman/rest/members.py138
-rw-r--r--src/mailman/rest/root.py4
-rw-r--r--src/mailman/rest/webservice.py210
7 files changed, 293 insertions, 246 deletions
diff --git a/src/mailman/rest/docs/lists.txt b/src/mailman/rest/docs/lists.txt
index ede0706fd..d04fed0b3 100644
--- a/src/mailman/rest/docs/lists.txt
+++ b/src/mailman/rest/docs/lists.txt
@@ -7,7 +7,7 @@ top level collection that can return all the mailing lists. There aren't any
yet though.
>>> dump_json('http://localhost:8001/3.0/lists')
- resource_type_link: http://localhost:8001/3.0/#lists
+ http_etag: "..."
start: None
total_size: 0
@@ -24,9 +24,8 @@ Create a mailing list in a domain and it's accessible via the API.
http_etag: "..."
list_name: test-one
real_name: Test-one
- resource_type_link: http://localhost:8001/3.0/#list
self_link: http://localhost:8001/3.0/lists/test-one@example.com
- resource_type_link: http://localhost:8001/3.0/#lists
+ http_etag: "..."
start: 0
total_size: 1
@@ -64,7 +63,6 @@ It is also available via the location given in the response.
http_etag: "..."
list_name: test-two
real_name: Test-two
- resource_type_link: http://localhost:8001/3.0/#list
self_link: http://localhost:8001/3.0/lists/test-two@example.com
However, you are not allowed to create a mailing list in a domain that does
diff --git a/src/mailman/rest/docs/membership.txt b/src/mailman/rest/docs/membership.txt
index 776713f5f..e86f598f1 100644
--- a/src/mailman/rest/docs/membership.txt
+++ b/src/mailman/rest/docs/membership.txt
@@ -9,7 +9,7 @@ returns all the members of all known mailing lists.
There are no mailing lists and no members yet.
>>> dump_json('http://localhost:8001/3.0/members')
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: None
total_size: 0
@@ -19,7 +19,7 @@ We create a mailing list, which starts out with no members.
>>> transaction.commit()
>>> dump_json('http://localhost:8001/3.0/members')
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: None
total_size: 0
@@ -49,9 +49,8 @@ the REST interface.
>>> dump_json('http://localhost:8001/3.0/members')
entry 0:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/bperson@example.com
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: 0
total_size: 1
@@ -62,13 +61,11 @@ the REST interface.
>>> dump_json('http://localhost:8001/3.0/members')
entry 0:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/bperson@example.com
entry 1:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/cperson@example.com
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: 0
total_size: 2
@@ -80,17 +77,14 @@ subscribes, she is returned first.
>>> dump_json('http://localhost:8001/3.0/members')
entry 0:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/aperson@example.com
entry 1:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/bperson@example.com
entry 2:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/cperson@example.com
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: 0
total_size: 3
@@ -104,25 +98,20 @@ address. Anna and Cris subscribe to this new mailing list.
>>> dump_json('http://localhost:8001/3.0/members')
entry 0:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/member/aperson@example.com
entry 1:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/member/cperson@example.com
entry 2:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/aperson@example.com
entry 3:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/bperson@example.com
entry 4:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/cperson@example.com
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: 0
total_size: 5
@@ -140,33 +129,26 @@ test-one mailing list.
>>> dump_json('http://localhost:8001/3.0/members')
entry 0:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/moderator/dperson@example.com
entry 1:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/member/aperson@example.com
entry 2:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/member/cperson@example.com
entry 3:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/owner/cperson@example.com
entry 4:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/aperson@example.com
entry 5:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/bperson@example.com
entry 6:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/test-one@example.com/member/cperson@example.com
- resource_type_link: http://localhost:8001/3.0/#members
+ http_etag: "..."
start: 0
total_size: 7
@@ -206,7 +188,6 @@ Elly is now a member of the mailing list.
...
entry 3:
http_etag: ...
- resource_type_link: http://localhost:8001/3.0/#member
self_link: http://localhost:8001/3.0/lists/alpha@example.com/member/eperson@example.com
...
diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py
index ed63834b9..32f010534 100644
--- a/src/mailman/rest/domains.py
+++ b/src/mailman/rest/domains.py
@@ -96,12 +96,12 @@ class AllDomains(_DomainBase):
if len(domains) == 0:
resource = dict(start=None, total_size=0)
return http.ok([], etag(resource))
- domain_data = [self._domain_data(domain) for domain in domains]
- # Tag this domain data, but ignore the results.
- [etag(data) for data in domain_data]
+ entries = [self._domain_data(domain) for domain in domains]
+ # Tag the domain entries, but use the dictionaries.
+ [etag(data) for data in entries]
resource = dict(
start=0,
total_size=len(domains),
- entries=domain_data,
+ entries=entries,
)
return http.ok([], etag(resource))
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py
new file mode 100644
index 000000000..682353373
--- /dev/null
+++ b/src/mailman/rest/lists.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2010 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""REST for mailing lists."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'AList',
+ 'AllLists',
+ ]
+
+
+from restish import http, resource
+from zope.component import getUtility
+
+from mailman.interfaces.domain import BadDomainSpecificationError
+from mailman.interfaces.listmanager import (
+ IListManager, ListAlreadyExistsError)
+from mailman.interfaces.member import MemberRole
+from mailman.rest.helpers import etag, path_to
+from mailman.rest.members import AMember
+
+
+
+def member_matcher(request, segments):
+ """A matcher of member URLs inside mailing lists.
+
+ e.g. /member/aperson@example.org
+ """
+ if len(segments) != 2:
+ return None
+ try:
+ role = MemberRole[segments[0]]
+ except ValueError:
+ # 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, address=segments[1]), ()
+
+# XXX 2010-02-24 barry Seems like contrary to the documentation, matchers
+# cannot be plain function, because matchers must have a .score attribute.
+# OTOH, I think they support regexps, so that might be a better way to go.
+member_matcher.score = ()
+
+
+
+class _ListBase(resource.Resource):
+ """Shared base class for mailing list representations."""
+
+ def _list_data(self, mlist):
+ """Return the list data for a single mailing list."""
+ return dict(
+ fqdn_listname=mlist.fqdn_listname,
+ host_name=mlist.host_name,
+ list_name=mlist.list_name,
+ real_name=mlist.real_name,
+ self_link=path_to('lists/{0}'.format(mlist.fqdn_listname)),
+ )
+
+ def _format_list(self, mlist):
+ """Format the mailing list for a single mailing list."""
+ return etag(self._list_data(mlist))
+
+
+class AList(_ListBase):
+ """A mailing list."""
+
+ def __init__(self, list_name):
+ self._mlist = getUtility(IListManager).get(list_name)
+
+ @resource.GET()
+ def mailing_list(self, request):
+ """Return a single mailing list end-point."""
+ if self._mlist is None:
+ return http.not_found()
+ return http.ok([], self._format_list(self._mlist))
+
+ @resource.child(member_matcher)
+ def member(self, request, segments, role, address):
+ return AMember(self._mlist, role, address)
+
+
+class AllLists(_ListBase):
+ """The mailing lists."""
+
+ @resource.POST()
+ def create(self, request):
+ """Create a new mailing list."""
+ # XXX 2010-02-23 barry Sanity check the POST arguments by
+ # introspection of the target method, or via descriptors.
+ list_manager = getUtility(IListManager)
+ try:
+ # webob gives this to us as a string, but we need unicodes.
+ kws = dict((key, unicode(value))
+ for key, value in request.POST.items())
+ mlist = list_manager.new(**kws)
+ except ListAlreadyExistsError:
+ return http.bad_request([], b'Mailing list exists')
+ except BadDomainSpecificationError as error:
+ return http.bad_request([], b'Domain does not exist {0}'.format(
+ error.domain))
+ # wsgiref wants headers to be bytes, not unicodes.
+ location = path_to('lists/{0}'.format(mlist.fqdn_listname))
+ # Include no extra headers or body.
+ return http.created(location, [], None)
+
+ @resource.GET()
+ def container(self, request):
+ """Return the /lists end-point."""
+ mlists = list(getUtility(IListManager))
+ if len(mlists) == 0:
+ resource = dict(start=None, total_size=0)
+ return http.ok([], etag(resource))
+ entries = [self._list_data(mlist) for mlist in mlists]
+ # Tag the list entries, but use the dictionaries.
+ [etag(data) for data in entries]
+ resource = dict(
+ start=0,
+ total_size=len(mlists),
+ entries=entries,
+ )
+ return http.ok([], etag(resource))
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
new file mode 100644
index 000000000..b18097935
--- /dev/null
+++ b/src/mailman/rest/members.py
@@ -0,0 +1,138 @@
+# Copyright (C) 2010 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""REST for members."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'AMember',
+ 'AllMembers',
+ ]
+
+
+from restish import http, resource
+from zope.component import getUtility
+
+from mailman.app.membership import delete_member
+from mailman.interfaces.address import InvalidEmailAddressError
+from mailman.interfaces.listmanager import NoSuchListError
+from mailman.interfaces.member import AlreadySubscribedError, MemberRole
+from mailman.interfaces.membership import ISubscriptionService
+from mailman.rest.helpers import etag, path_to
+
+
+
+class _MemberBase(resource.Resource):
+ """Shared base class for member representations."""
+
+ def _member_data(self, member):
+ """Return the member data for a single member."""
+ enum, dot, role = str(member.role).partition('.')
+ return dict(
+ self_link=path_to('lists/{0}/{1}/{2}'.format(
+ member.mailing_list, role, member.address.address)),
+ )
+
+ def _format_member(self, member):
+ """Format the data for a single member."""
+ return etag(self._member_data(member))
+
+
+class AMember(_MemberBase):
+ """A member."""
+
+ def __init__(self, mailing_list, role, address):
+ self._mlist = mailing_list
+ self._role = role
+ self._address = address
+ # XXX 2010-02-24 barry There should be a more direct way to get a
+ # member out of a mailing list.
+ if self._role is MemberRole.member:
+ roster = self._mlist.members
+ elif self._role is MemberRole.owner:
+ roster = self._mlist.owners
+ elif self._role is MemberRole.moderator:
+ roster = self._mlist.moderators
+ else:
+ raise AssertionError(
+ 'Undefined MemberRole: {0}'.format(self._role))
+ self._member = roster.get_member(self._address)
+
+ @resource.GET()
+ def member(self, request):
+ """Return a single member end-point."""
+ return http.ok([], self._format_member(self._member))
+
+ @resource.DELETE()
+ def delete(self, request):
+ """Delete the member (i.e. unsubscribe)."""
+ # Leaving a list is a bit different than deleting a moderator or
+ # owner. Handle the former case first. For now too, we will not send
+ # an admin or user notification.
+ if self._role is MemberRole.member:
+ delete_member(self._mlist, self._address, False, False)
+ else:
+ self._member.unsubscribe()
+ return http.ok([], '')
+
+
+class AllMembers(_MemberBase):
+ """The members."""
+
+ @resource.POST()
+ def create(self, request):
+ """Create a new member."""
+ # XXX 2010-02-23 barry Sanity check the POST arguments by
+ # introspection of the target method, or via descriptors.
+ service = getUtility(ISubscriptionService)
+ try:
+ # webob gives this to us as a string, but we need unicodes.
+ kws = dict((key, unicode(value))
+ for key, value in request.POST.items())
+ member = service.join(**kws)
+ except AlreadySubscribedError:
+ return http.bad_request([], b'Member already subscribed')
+ except NoSuchListError:
+ return http.bad_request([], b'No such list')
+ except InvalidEmailAddressError:
+ return http.bad_request([], b'Invalid email address')
+ except ValueError as error:
+ return http.bad_request([], str(error))
+ # wsgiref wants headers to be bytes, not unicodes.
+ location = path_to('lists/{0}/member/{1}'.format(
+ member.mailing_list, member.address.address))
+ # Include no extra headers or body.
+ return http.created(location, [], None)
+
+ @resource.GET()
+ def container(self, request):
+ """Return the /members end-point."""
+ members = list(getUtility(ISubscriptionService))
+ if len(members) == 0:
+ resource = dict(start=None, total_size=0)
+ return http.ok([], etag(resource))
+ entries = [self._member_data(member) for member in members]
+ # Tag the domain entries, but use the dictionaries.
+ [etag(data) for data in entries]
+ resource = dict(
+ start=0,
+ total_size=len(members),
+ entries=entries,
+ )
+ return http.ok([], etag(resource))
diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py
index e524f3632..6835586b8 100644
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -31,8 +31,8 @@ from mailman.config import config
from mailman.core.system import system
from mailman.rest.domains import ADomain, AllDomains
from mailman.rest.helpers import etag, path_to
-from mailman.rest.webservice import (
- AList, AllLists, AllMembers)
+from mailman.rest.lists import AList, AllLists
+from mailman.rest.members import AllMembers
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index 403948de8..c8aa470b9 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -52,213 +52,3 @@ log = logging.getLogger('mailman.http')
-class _ListBase(resource.Resource):
- """Shared base class for mailing list representations."""
-
- def _format_list(self, mlist):
- """Format the mailing list for a single domain."""
- list_data = dict(
- fqdn_listname=mlist.fqdn_listname,
- host_name=mlist.host_name,
- list_name=mlist.list_name,
- real_name=mlist.real_name,
- resource_type_link='http://localhost:8001/3.0/#list',
- self_link='http://localhost:8001/3.0/lists/{0}'.format(
- mlist.fqdn_listname),
- )
- etag = hashlib.sha1(repr(list_data)).hexdigest()
- list_data['http_etag'] = '"{0}"'.format(etag)
- return list_data
-
-
-def member_matcher(request, segments):
- """A matcher of member URLs inside mailing lists.
-
- e.g. /member/aperson@example.org
- """
- if len(segments) != 2:
- return None
- try:
- role = MemberRole[segments[0]]
- except ValueError:
- # Not a valid role.
- return None
- # No more segments.
- return (), dict(role=role, address=segments[1]), ()
-
-# XXX 2010-02-24 barry Seems like contrary to the documentation, matchers
-# cannot be plain function, because matchers must have a .score attribute.
-# OTOH, I think they support regexps, so that might be a better way to go.
-member_matcher.score = ()
-
-
-class AList(_ListBase):
- """A mailing list."""
-
- def __init__(self, list_name):
- self._mlist = getUtility(IListManager).get(list_name)
-
- @resource.GET()
- def mailing_list(self, request):
- """Return a single mailing list end-point."""
- if self._mlist is None:
- return http.not_found()
- return http.ok([], json.dumps(self._format_list(self._mlist)))
-
- @resource.child(member_matcher)
- def member(self, request, segments, role, address):
- return AMember(self._mlist, role, address)
-
-
-class AllLists(_ListBase):
- """The mailing lists."""
-
- @resource.POST()
- def create(self, request):
- """Create a new mailing list."""
- # XXX 2010-02-23 barry Sanity check the POST arguments by
- # introspection of the target method, or via descriptors.
- list_manager = getUtility(IListManager)
- try:
- # webob gives this to us as a string, but we need unicodes.
- kws = dict((key, unicode(value))
- for key, value in request.POST.items())
- mlist = list_manager.new(**kws)
- except ListAlreadyExistsError:
- return http.bad_request([], b'Mailing list exists')
- except BadDomainSpecificationError as error:
- return http.bad_request([], b'Domain does not exist {0}'.format(
- error.domain))
- # wsgiref wants headers to be bytes, not unicodes.
- location = b'http://localhost:8001/3.0/lists/{0}'.format(
- mlist.fqdn_listname)
- # Include no extra headers or body.
- return http.created(location, [], None)
-
- @resource.GET()
- def container(self, request):
- """Return the /lists end-point."""
- mlists = list(getUtility(IListManager))
- if len(mlists) == 0:
- return http.ok(
- [], json.dumps(dict(resource_type_link=
- 'http://localhost:8001/3.0/#lists',
- start=None,
- total_size=0)))
- entries = []
- response = dict(
- resource_type_link='http://localhost:8001/3.0/#lists',
- start=0,
- total_size=len(mlists),
- entries=entries,
- )
- for mlist in mlists:
- list_data = self._format_list(mlist)
- entries.append(list_data)
- return http.ok([], json.dumps(response))
-
-
-
-class _MemberBase(resource.Resource):
- """Shared base class for member representations."""
-
- def _format_member(self, member):
- """Format the data for a single member."""
- enum, dot, role = str(member.role).partition('.')
- member_data = dict(
- resource_type_link='http://localhost:8001/3.0/#member',
- self_link='http://localhost:8001/3.0/lists/{0}/{1}/{2}'.format(
- member.mailing_list, role, member.address.address),
- )
- etag = hashlib.sha1(repr(member_data)).hexdigest()
- member_data['http_etag'] = '"{0}"'.format(etag)
- return member_data
-
-
-class AMember(_MemberBase):
- """A member."""
-
- def __init__(self, mailing_list, role, address):
- self._mlist = mailing_list
- self._role = role
- self._address = address
- # XXX 2010-02-24 barry There should be a more direct way to get a
- # member out of a mailing list.
- if self._role is MemberRole.member:
- roster = self._mlist.members
- elif self._role is MemberRole.owner:
- roster = self._mlist.owners
- elif self._role is MemberRole.moderator:
- roster = self._mlist.moderators
- else:
- raise AssertionError(
- 'Undefined MemberRole: {0}'.format(self._role))
- self._member = roster.get_member(self._address)
-
- @resource.GET()
- def member(self, request):
- """Return a single member end-point."""
- return http.ok([], json.dumps(self._format_member(self._member)))
-
- @resource.DELETE()
- def delete(self, request):
- """Delete the member (i.e. unsubscribe)."""
- # Leaving a list is a bit different than deleting a moderator or
- # owner. Handle the former case first. For now too, we will not send
- # an admin or user notification.
- if self._role is MemberRole.member:
- delete_member(self._mlist, self._address, False, False)
- else:
- self._member.unsubscribe()
- return http.ok([], '')
-
-
-class AllMembers(_MemberBase):
- """The members."""
-
- @resource.POST()
- def create(self, request):
- """Create a new member."""
- # XXX 2010-02-23 barry Sanity check the POST arguments by
- # introspection of the target method, or via descriptors.
- service = getUtility(ISubscriptionService)
- try:
- # webob gives this to us as a string, but we need unicodes.
- kws = dict((key, unicode(value))
- for key, value in request.POST.items())
- member = service.join(**kws)
- except AlreadySubscribedError:
- return http.bad_request([], b'Member already subscribed')
- except NoSuchListError:
- return http.bad_request([], b'No such list')
- except InvalidEmailAddressError:
- return http.bad_request([], b'Invalid email address')
- except ValueError as error:
- return http.bad_request([], str(error))
- # wsgiref wants headers to be bytes, not unicodes.
- location = b'http://localhost:8001/3.0/lists/{0}/member/{1}'.format(
- member.mailing_list, member.address.address)
- # Include no extra headers or body.
- return http.created(location, [], None)
-
- @resource.GET()
- def container(self, request):
- """Return the /members end-point."""
- members = list(getUtility(ISubscriptionService))
- if len(members) == 0:
- return http.ok(
- [], json.dumps(dict(resource_type_link=
- 'http://localhost:8001/3.0/#members',
- start=None,
- total_size=0)))
- entries = []
- response = dict(
- resource_type_link='http://localhost:8001/3.0/#members',
- start=0,
- total_size=len(members),
- entries=entries,
- )
- for member in members:
- member_data = self._format_member(member)
- entries.append(member_data)
- return http.ok([], json.dumps(response))