summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/interfaces/domain.py4
-rw-r--r--src/mailman/interfaces/listmanager.py42
-rw-r--r--src/mailman/model/listmanager.py15
-rw-r--r--src/mailman/rest/docs/lists.txt5
-rw-r--r--src/mailman/rest/webservice.py102
5 files changed, 138 insertions, 30 deletions
diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py
index a8770b664..b7fc1c91f 100644
--- a/src/mailman/interfaces/domain.py
+++ b/src/mailman/interfaces/domain.py
@@ -37,6 +37,10 @@ from mailman.core.i18n import _
class BadDomainSpecificationError(MailmanError):
"""The specification of a virtual domain is invalid or duplicated."""
+ def __init__(self, domain):
+ super(BadDomainSpecificationError, self).__init__(domain)
+ self.domain = domain
+
class IDomain(Interface):
diff --git a/src/mailman/interfaces/listmanager.py b/src/mailman/interfaces/listmanager.py
index f47fe658e..f83791079 100644
--- a/src/mailman/interfaces/listmanager.py
+++ b/src/mailman/interfaces/listmanager.py
@@ -73,6 +73,25 @@ class IListManager(Interface):
:raise `ListAlreadyExistsError` if the named list already exists.
"""
+
+ def new(fqdn_listname):
+ """Add a new mailing list.
+
+ The mailing may not exist yet, but the domain specified in
+ `fqdn_listname` must exist. This is a higher level interface than
+ create() and should generally be used instead of that method.
+
+ :param fqdn_listname: The fully qualified name for the new
+ mailing list.
+ :type fqdn_listname: string
+ :return: The new mailing list
+ :rtype: `IMailingList`
+ :raises `BadDomainSpecificationError`: when the hostname part of
+ `fqdn_listname` does not exist.
+ :raises `ListAlreadyExistsError`: when the mailing list already
+ exists.
+ """
+
def get(fqdn_listname):
"""Return the mailing list with the given name, if it exists.
@@ -93,6 +112,12 @@ class IListManager(Interface):
"""An iterator over all the mailing list objects managed by this list
manager.""")
+ def __iter__():
+ """An iterator over all the mailing lists.
+
+ :return: iterator over `IMailingList`.
+ """
+
names = Attribute(
"""An iterator over the fully qualified list names of all mailing
lists managed by this list manager.""")
@@ -103,20 +128,3 @@ class IListManager(Interface):
:return: The list of all known mailing lists.
:rtype: list of `IMailingList`
"""
-
- def new(fqdn_listname):
- """Add a new maling list.
-
- The mailing may not exist yet, but the domain specified in
- `fqdn_listname` must exist.
-
- :param fqdn_listname: The fully qualified name for the new
- mailing list.
- :type fqdn_listname: string
- :return: The new mailing list
- :rtype: `IMailingList`
- :raises `BadDomainSpecificationError`: when the hostname part of
- `fqdn_listname` does not exist.
- :raises `ListAlreadyExistsError`: when the mailing list already
- exists.
- """
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index b8bfa85ee..1bb2366b5 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -59,6 +59,11 @@ class ListManager:
config.db.store.add(mlist)
return mlist
+ def new(self, fqdn_listname):
+ """See `IListManager."""
+ from mailman.app.lifecycle import create_list
+ return create_list(fqdn_listname)
+
def get(self, fqdn_listname):
"""See `IListManager`."""
listname, at, hostname = fqdn_listname.partition('@')
@@ -80,6 +85,11 @@ class ListManager:
for fqdn_listname in self.names:
yield self.get(fqdn_listname)
+ def __iter__(self):
+ """See `IListManager`."""
+ for fqdn_listname in self.names:
+ yield self.get(fqdn_listname)
+
@property
def names(self):
"""See `IListManager`."""
@@ -90,8 +100,3 @@ class ListManager:
"""See `IListManager`."""
# lazr.restful will not allow this to be a generator.
return list(self.mailing_lists)
-
- def new(self, fqdn_listname):
- """See `IListManager."""
- from mailman.app.lifecycle import create_list
- return create_list(fqdn_listname)
diff --git a/src/mailman/rest/docs/lists.txt b/src/mailman/rest/docs/lists.txt
index 460ca3585..bb0824f7a 100644
--- a/src/mailman/rest/docs/lists.txt
+++ b/src/mailman/rest/docs/lists.txt
@@ -44,12 +44,9 @@ instead of posting directly to the URL.
... })
URL: http://localhost:8001/3.0/lists
content-length: 0
- content-type: text/plain;charset=utf-8
date: ...
location: http://localhost:8001/3.0/lists/test-two@example.com
- server: WSGIServer/... Python/...
- x-content-type-warning: guessed from content
- x-powered-by: Zope (www.zope.org), Python (www.python.org)
+ ...
The mailing list exists in the database.
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index 8a1e919bf..40e4a5ef6 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -43,7 +43,7 @@ from mailman.config import config
from mailman.core.system import system
from mailman.interfaces.domain import (
BadDomainSpecificationError, IDomain, IDomainManager)
-from mailman.interfaces.listmanager import IListManager
+from mailman.interfaces.listmanager import ListAlreadyExistsError, IListManager
from mailman.interfaces.mailinglist import IMailingList
from mailman.interfaces.member import IMember
from mailman.interfaces.membership import ISubscriptionService
@@ -88,6 +88,15 @@ class TopLevel(resource.Resource):
else:
return http.bad_request()
+ @resource.child()
+ def lists(self, request, segments):
+ if len(segments) == 0:
+ return AllLists()
+ elif len(segments) == 1:
+ return AList(segments[0]), []
+ else:
+ return http.bad_request()
+
class _DomainBase(resource.Resource):
"""Shared base class for domain representations."""
@@ -143,11 +152,11 @@ class AllDomains(_DomainBase):
domain = domain_manager.add(**kws)
except BadDomainSpecificationError:
return http.bad_request([], 'Domain exists')
- # wsgiref wants headers to be strings, not unicodes.
- location = 'http://localhost:8001/3.0/domains/{0}'.format(
+ # wsgiref wants headers to be bytes, not unicodes.
+ location = b'http://localhost:8001/3.0/domains/{0}'.format(
domain.email_host)
# Include no extra headers or body.
- return http.created(str(location), [], None)
+ return http.created(location, [], None)
@resource.GET()
def container(self, request):
@@ -172,6 +181,91 @@ class AllDomains(_DomainBase):
return http.ok([], json.dumps(response))
+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
+
+
+class AList(_ListBase):
+ """A mailing list."""
+
+ def __init__(self, mlist):
+ self._mlist = mlist
+
+ @resource.GET()
+ def mailing_list(self, request):
+ """Return a single mailing list end-point."""
+ mlist = getUtility(IListManager).get(self._mlist)
+ if mlist is None:
+ return http.not_found()
+ return http.ok([], json.dumps(self._format_list(mlist)))
+
+
+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:
+ # Hmmm... webob gives this to us as a string, but we need
+ # unicodes. For backward compatibility with lazr.restful style
+ # requests, ignore any ws.op parameter.
+ kws = dict((key, unicode(value))
+ for key, value in request.POST.items()
+ if key != 'ws.op')
+ 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 AdminWebServiceRootResource(RootResource):
## """The lazr.restful non-versioned root resource."""