summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2010-02-25 21:07:27 -0500
committerBarry Warsaw2010-02-25 21:07:27 -0500
commitc231eb4a8c1bd593804a3a2f05f07966dcd73f18 (patch)
treebcfbf3f0a66f1e55fffc3289aec7389ee9c79227
parent70dd8a96cc0e01b42737b46e30cf37b5c8fa0747 (diff)
downloadmailman-c231eb4a8c1bd593804a3a2f05f07966dcd73f18.tar.gz
mailman-c231eb4a8c1bd593804a3a2f05f07966dcd73f18.tar.zst
mailman-c231eb4a8c1bd593804a3a2f05f07966dcd73f18.zip
-rw-r--r--src/mailman/rest/docs/domains.txt4
-rw-r--r--src/mailman/rest/docs/lists.txt2
-rw-r--r--src/mailman/rest/docs/membership.txt4
-rw-r--r--src/mailman/rest/domains.py33
-rw-r--r--src/mailman/rest/helpers.py50
-rw-r--r--src/mailman/rest/lists.py33
-rw-r--r--src/mailman/rest/members.py31
7 files changed, 87 insertions, 70 deletions
diff --git a/src/mailman/rest/docs/domains.txt b/src/mailman/rest/docs/domains.txt
index 86c868530..b8e0170b0 100644
--- a/src/mailman/rest/docs/domains.txt
+++ b/src/mailman/rest/docs/domains.txt
@@ -16,8 +16,8 @@ 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')
- http_etag: "f62b4cab6d4bfa731d5ff091dde29d318a3234a8"
- start: None
+ http_etag: "..."
+ start: 0
total_size: 0
Once a domain is added though, it is accessible through the API.
diff --git a/src/mailman/rest/docs/lists.txt b/src/mailman/rest/docs/lists.txt
index d04fed0b3..6abf29a1d 100644
--- a/src/mailman/rest/docs/lists.txt
+++ b/src/mailman/rest/docs/lists.txt
@@ -8,7 +8,7 @@ yet though.
>>> dump_json('http://localhost:8001/3.0/lists')
http_etag: "..."
- start: None
+ start: 0
total_size: 0
Create a mailing list in a domain and it's accessible via the API.
diff --git a/src/mailman/rest/docs/membership.txt b/src/mailman/rest/docs/membership.txt
index e86f598f1..70d4384ce 100644
--- a/src/mailman/rest/docs/membership.txt
+++ b/src/mailman/rest/docs/membership.txt
@@ -10,7 +10,7 @@ There are no mailing lists and no members yet.
>>> dump_json('http://localhost:8001/3.0/members')
http_etag: "..."
- start: None
+ start: 0
total_size: 0
We create a mailing list, which starts out with no members.
@@ -20,7 +20,7 @@ We create a mailing list, which starts out with no members.
>>> dump_json('http://localhost:8001/3.0/members')
http_etag: "..."
- start: None
+ start: 0
total_size: 0
diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py
index 32f010534..8b7cd2699 100644
--- a/src/mailman/rest/domains.py
+++ b/src/mailman/rest/domains.py
@@ -31,15 +31,15 @@ from zope.component import getUtility
from mailman.interfaces.domain import (
BadDomainSpecificationError, IDomainManager)
-from mailman.rest.helpers import etag, path_to
+from mailman.rest.helpers import CollectionMixin, etag, path_to
-class _DomainBase(resource.Resource):
+class _DomainBase(resource.Resource, CollectionMixin):
"""Shared base class for domain representations."""
- def _domain_data(self, domain):
- """Return the domain data for a single domain."""
+ def _resource_as_dict(self, domain):
+ """See `CollectionMixin`."""
return dict(
base_url=domain.base_url,
contact_address=domain.contact_address,
@@ -49,9 +49,9 @@ class _DomainBase(resource.Resource):
url_host=domain.url_host,
)
- def _format_domain(self, domain):
- """Format the data for a single domain."""
- return etag(self._domain_data(domain))
+ def _get_collection(self, request):
+ """See `CollectionMixin`."""
+ return list(getUtility(IDomainManager))
class ADomain(_DomainBase):
@@ -66,7 +66,7 @@ class ADomain(_DomainBase):
domain = getUtility(IDomainManager).get(self._domain)
if domain is None:
return http.not_found()
- return http.ok([], self._format_domain(domain))
+ return http.ok([], self._resource_as_json(domain))
class AllDomains(_DomainBase):
@@ -90,18 +90,7 @@ class AllDomains(_DomainBase):
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))
- 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=entries,
- )
+ def collection(self, request):
+ """/domains"""
+ resource = self._make_collection(request)
return http.ok([], etag(resource))
diff --git a/src/mailman/rest/helpers.py b/src/mailman/rest/helpers.py
index fac4ae4f1..87614d1f0 100644
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -21,6 +21,7 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
+ 'ContainerMixin',
'etag',
'path_to',
]
@@ -71,3 +72,52 @@ def etag(resource):
etag = hashlib.sha1(repr(resource)).hexdigest()
resource['http_etag'] = '"{0}"'.format(etag)
return json.dumps(resource)
+
+
+
+class CollectionMixin:
+ """Mixin class for common collection-ish things."""
+
+ def _resource_as_dict(self, resource):
+ """Return the dictionary representation of a resource.
+
+ This must be implemented by subclasses.
+
+ :param resource: The resource object.
+ :type resource: object
+ :return: The representation of the resource.
+ :rtype: dict
+ """
+ raise NotImplementedError
+
+ def _resource_as_json(self, resource):
+ """Return the JSON formatted representation of the resource."""
+ return etag(self._resource_as_dict(resource))
+
+ def _get_collection(self, request):
+ """Return the collection as a concrete list.
+
+ This must be implemented by subclasses.
+
+ :param request: A restish request.
+ :return: The collection
+ :rtype: list
+ """
+ raise NotImplementedError
+
+ def _make_collection(self, request):
+ """Provide the collection to restish."""
+ collection = self._get_collection(request)
+ if len(collection) == 0:
+ return dict(start=0, total_size=0)
+ else:
+ entries = [self._resource_as_dict(resource)
+ for resource in collection]
+ # Tag the resources but use the dictionaries.
+ [etag(resource) for resource in entries]
+ # Create the collection resource
+ return dict(
+ start=0,
+ total_size=len(collection),
+ entries=entries,
+ )
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py
index 682353373..b232cc5bc 100644
--- a/src/mailman/rest/lists.py
+++ b/src/mailman/rest/lists.py
@@ -33,7 +33,7 @@ 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.helpers import CollectionMixin, etag, path_to
from mailman.rest.members import AMember
@@ -62,11 +62,11 @@ member_matcher.score = ()
-class _ListBase(resource.Resource):
+class _ListBase(resource.Resource, CollectionMixin):
"""Shared base class for mailing list representations."""
- def _list_data(self, mlist):
- """Return the list data for a single mailing list."""
+ def _resource_as_dict(self, mlist):
+ """See `CollectionMixin`."""
return dict(
fqdn_listname=mlist.fqdn_listname,
host_name=mlist.host_name,
@@ -75,9 +75,9 @@ class _ListBase(resource.Resource):
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))
+ def _get_collection(self, request):
+ """See `CollectionMixin`."""
+ return list(getUtility(IListManager))
class AList(_ListBase):
@@ -91,7 +91,7 @@ class AList(_ListBase):
"""Return a single mailing list end-point."""
if self._mlist is None:
return http.not_found()
- return http.ok([], self._format_list(self._mlist))
+ return http.ok([], self._resource_as_json(self._mlist))
@resource.child(member_matcher)
def member(self, request, segments, role, address):
@@ -123,18 +123,7 @@ class AllLists(_ListBase):
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,
- )
+ def collection(self, request):
+ """/lists"""
+ resource = self._make_collection(request)
return http.ok([], etag(resource))
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index b18097935..ace1ff3cb 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -34,24 +34,24 @@ 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
+from mailman.rest.helpers import CollectionMixin, etag, path_to
-class _MemberBase(resource.Resource):
+class _MemberBase(resource.Resource, CollectionMixin):
"""Shared base class for member representations."""
- def _member_data(self, member):
- """Return the member data for a single member."""
+ def _resource_as_dict(self, member):
+ """See `CollectionMixin`."""
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))
+ def _get_collection(self, request):
+ """See `CollectionMixin`."""
+ return list(getUtility(ISubscriptionService))
class AMember(_MemberBase):
@@ -77,7 +77,7 @@ class AMember(_MemberBase):
@resource.GET()
def member(self, request):
"""Return a single member end-point."""
- return http.ok([], self._format_member(self._member))
+ return http.ok([], self._resource_as_json(self._member))
@resource.DELETE()
def delete(self, request):
@@ -122,17 +122,6 @@ class AllMembers(_MemberBase):
@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,
- )
+ """/members"""
+ resource = self._make_collection(request)
return http.ok([], etag(resource))