summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/rest/docs/domains.txt13
-rw-r--r--src/mailman/rest/domains.py107
-rw-r--r--src/mailman/rest/helpers.py4
-rw-r--r--src/mailman/rest/root.py14
-rw-r--r--src/mailman/rest/webservice.py81
5 files changed, 122 insertions, 97 deletions
diff --git a/src/mailman/rest/docs/domains.txt b/src/mailman/rest/docs/domains.txt
index 0bce5fa54..86c868530 100644
--- a/src/mailman/rest/docs/domains.txt
+++ b/src/mailman/rest/docs/domains.txt
@@ -16,7 +16,7 @@ The REST API can be queried for the set of known domains, of which there are
initially none.
>>> dump_json('http://localhost:8001/3.0/domains')
- resource_type_link: http://localhost:8001/3.0/#domains
+ http_etag: "f62b4cab6d4bfa731d5ff091dde29d318a3234a8"
start: None
total_size: 0
@@ -36,10 +36,9 @@ Once a domain is added though, it is accessible through the API.
description: An example domain
email_host: example.com
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/example.com
url_host: lists.example.com
- resource_type_link: http://localhost:8001/3.0/#domains
+ http_etag: "..."
start: 0
total_size: 1
@@ -68,7 +67,6 @@ At the top level, all domains are returned as separate entries.
description: An example domain
email_host: example.com
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/example.com
url_host: lists.example.com
entry 1:
@@ -77,7 +75,6 @@ At the top level, all domains are returned as separate entries.
description: None
email_host: example.org
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/example.org
url_host: mail.example.org
entry 2:
@@ -86,10 +83,9 @@ At the top level, all domains are returned as separate entries.
description: Porkmasters
email_host: lists.example.net
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/lists.example.net
url_host: example.net
- resource_type_link: http://localhost:8001/3.0/#domains
+ http_etag: "..."
start: 0
total_size: 3
@@ -106,7 +102,6 @@ self_links from the above collection.
description: Porkmasters
email_host: lists.example.net
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/lists.example.net
url_host: example.net
@@ -139,7 +134,6 @@ Now the web service knows about our new domain.
description: None
email_host: lists.example.com
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/lists.example.com
url_host: lists.example.com
@@ -173,7 +167,6 @@ address.
description: My new domain
email_host: my.example.com
http_etag: "..."
- resource_type_link: http://localhost:8001/3.0/#domain
self_link: http://localhost:8001/3.0/domains/my.example.com
url_host: allmy.example.com
diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py
new file mode 100644
index 000000000..ed63834b9
--- /dev/null
+++ b/src/mailman/rest/domains.py
@@ -0,0 +1,107 @@
+# 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 domains."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'ADomain',
+ 'AllDomains',
+ ]
+
+
+from restish import http, resource
+from zope.component import getUtility
+
+from mailman.interfaces.domain import (
+ BadDomainSpecificationError, IDomainManager)
+from mailman.rest.helpers import etag, path_to
+
+
+
+class _DomainBase(resource.Resource):
+ """Shared base class for domain representations."""
+
+ def _domain_data(self, domain):
+ """Return the domain data for a single domain."""
+ return dict(
+ base_url=domain.base_url,
+ contact_address=domain.contact_address,
+ description=domain.description,
+ email_host=domain.email_host,
+ self_link=path_to('domains/{0}'.format(domain.email_host)),
+ url_host=domain.url_host,
+ )
+
+ def _format_domain(self, domain):
+ """Format the data for a single domain."""
+ return etag(self._domain_data(domain))
+
+
+class ADomain(_DomainBase):
+ """A domain."""
+
+ def __init__(self, domain):
+ self._domain = domain
+
+ @resource.GET()
+ def domain(self, request):
+ """Return a single domain end-point."""
+ domain = getUtility(IDomainManager).get(self._domain)
+ if domain is None:
+ return http.not_found()
+ return http.ok([], self._format_domain(domain))
+
+
+class AllDomains(_DomainBase):
+ """The domains."""
+
+ @resource.POST()
+ def create(self, request):
+ """Create a new domain."""
+ # XXX 2010-02-23 barry Sanity check the POST arguments by
+ # introspection of the target method, or via descriptors.
+ domain_manager = getUtility(IDomainManager)
+ 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())
+ domain = domain_manager.add(**kws)
+ except BadDomainSpecificationError:
+ return http.bad_request([], 'Domain exists')
+ location = path_to('domains/{0}'.format(domain.email_host))
+ # Include no extra headers or body.
+ return http.created(location, [], None)
+
+ @resource.GET()
+ def container(self, request):
+ """Return the /domains end-point."""
+ domains = list(getUtility(IDomainManager))
+ 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]
+ resource = dict(
+ start=0,
+ total_size=len(domains),
+ entries=domain_data,
+ )
+ return http.ok([], etag(resource))
diff --git a/src/mailman/rest/helpers.py b/src/mailman/rest/helpers.py
index d1afdb0d9..fac4ae4f1 100644
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -41,9 +41,9 @@ def path_to(resource):
system base URI.
:type resource: string
:return: The full path to the resource.
- :rtype: string
+ :rtype: bytes
"""
- return '{0}://{1}:{2}/{3}/{4}'.format(
+ return b'{0}://{1}:{2}/{3}/{4}'.format(
('https' if as_boolean(config.webservice.use_https) else 'http'),
config.webservice.hostname,
config.webservice.port,
diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py
index e3ba1b62e..e524f3632 100644
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -25,16 +25,14 @@ __all__ = [
]
-import json
-import hashlib
-
from restish import http, resource
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 (
- ADomain, AList, AllDomains, AllLists, AllMembers)
+ AList, AllLists, AllMembers)
@@ -66,6 +64,9 @@ class TopLevel(resource.Resource):
@resource.child()
def domains(self, request, segments):
+ """/<api>/domains
+ /<api>/domains/<domain>
+ """
if len(segments) == 0:
return AllDomains()
elif len(segments) == 1:
@@ -75,6 +76,10 @@ class TopLevel(resource.Resource):
@resource.child()
def lists(self, request, segments):
+ """/<api>/lists
+ /<api>/lists/<list>
+ /<api>/lists/<list>/...
+ """
if len(segments) == 0:
return AllLists()
else:
@@ -83,6 +88,7 @@ class TopLevel(resource.Resource):
@resource.child()
def members(self, request, segments):
+ """/<api>/members"""
if len(segments) == 0:
return AllMembers()
return http.bad_request()
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index 03c2097af..403948de8 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -52,87 +52,6 @@ log = logging.getLogger('mailman.http')
-class _DomainBase(resource.Resource):
- """Shared base class for domain representations."""
-
- def _format_domain(self, domain):
- """Format the data for a single domain."""
- domain_data = dict(
- base_url=domain.base_url,
- contact_address=domain.contact_address,
- description=domain.description,
- email_host=domain.email_host,
- resource_type_link='http://localhost:8001/3.0/#domain',
- self_link='http://localhost:8001/3.0/domains/{0}'.format(
- domain.email_host),
- url_host=domain.url_host,
- )
- etag = hashlib.sha1(repr(domain_data)).hexdigest()
- domain_data['http_etag'] = '"{0}"'.format(etag)
- return domain_data
-
-
-class ADomain(_DomainBase):
- """A domain."""
-
- def __init__(self, domain):
- self._domain = domain
-
- @resource.GET()
- def domain(self, request):
- """Return a single domain end-point."""
- domain = getUtility(IDomainManager).get(self._domain)
- if domain is None:
- return http.not_found()
- return http.ok([], json.dumps(self._format_domain(domain)))
-
-
-class AllDomains(_DomainBase):
- """The domains."""
-
- @resource.POST()
- def create(self, request):
- """Create a new domain."""
- # XXX 2010-02-23 barry Sanity check the POST arguments by
- # introspection of the target method, or via descriptors.
- domain_manager = getUtility(IDomainManager)
- 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())
- domain = domain_manager.add(**kws)
- except BadDomainSpecificationError:
- return http.bad_request([], 'Domain exists')
- # 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(location, [], None)
-
- @resource.GET()
- def container(self, request):
- """Return the /domains end-point."""
- domains = list(getUtility(IDomainManager))
- if len(domains) == 0:
- return http.ok(
- [], json.dumps(dict(resource_type_link=
- 'http://localhost:8001/3.0/#domains',
- start=None,
- total_size=0)))
- entries = []
- response = dict(
- resource_type_link='http://localhost:8001/3.0/#domains',
- start=0,
- total_size=len(domains),
- entries=entries,
- )
- for domain in domains:
- domain_data = self._format_domain(domain)
- entries.append(domain_data)
- return http.ok([], json.dumps(response))
-
-
-
class _ListBase(resource.Resource):
"""Shared base class for mailing list representations."""