diff options
| author | Barry Warsaw | 2011-08-30 22:04:14 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2011-08-30 22:04:14 -0400 |
| commit | 232ac1d8af1b6d483a1bd7aa2bc5ae15e0450bdf (patch) | |
| tree | e1e0b843a849bfaccf2d006d9ee1340a99a1eee1 /src | |
| parent | 0664713d4f7e30b0b56b1ce00ccf3367f416c901 (diff) | |
| parent | d1404b057df7f7ce20df7dac13eb18eba4eb02b4 (diff) | |
| download | mailman-232ac1d8af1b6d483a1bd7aa2bc5ae15e0450bdf.tar.gz mailman-232ac1d8af1b6d483a1bd7aa2bc5ae15e0450bdf.tar.zst mailman-232ac1d8af1b6d483a1bd7aa2bc5ae15e0450bdf.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 3 | ||||
| -rw-r--r-- | src/mailman/interfaces/domain.py | 3 | ||||
| -rw-r--r-- | src/mailman/model/docs/domains.rst | 24 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 10 | ||||
| -rw-r--r-- | src/mailman/rest/docs/domains.rst | 34 | ||||
| -rw-r--r-- | src/mailman/rest/docs/lists.rst | 20 | ||||
| -rw-r--r-- | src/mailman/rest/domains.py | 12 | ||||
| -rw-r--r-- | src/mailman/rest/lists.py | 19 | ||||
| -rw-r--r-- | src/mailman/rest/root.py | 5 | ||||
| -rw-r--r-- | src/mailman/rest/tests/test_domains.py | 72 |
10 files changed, 198 insertions, 4 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index 54b05f028..597387b40 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -39,6 +39,9 @@ REST * New REST resource http://.../members/find can be POSTed to in order to find member records. Optional arguments are `subscriber` (email address to search for), `fqdn_listname`, and `role` (i.e. MemberRole). (LP: #799612) + * New REST resource http://.../<domain>/lists can be GETed in order to find + all the mailing lists in a specific domain (LP: #829765). Given by + Stephen A. Goss. * Fixed /lists/<fqdn_listname>/<role>/<email> (LP: #825570) * Remove role plurals from /lists/<fqdn_listname/rosters/<role> * Fixed incorrect error code for /members/<bogus> (LP: #821020). Given by diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py index 0e0ea72ae..e0423f73b 100644 --- a/src/mailman/interfaces/domain.py +++ b/src/mailman/interfaces/domain.py @@ -64,6 +64,9 @@ class IDomain(Interface): The contact address for the human at this domain. E.g. postmaster@example.com""") + mailing_lists = Attribute( + 'All mailing lists for this domain.') + def confirm_url(token=''): """The url used for various forms of confirmation. diff --git a/src/mailman/model/docs/domains.rst b/src/mailman/model/docs/domains.rst index 4fa39aa2f..878e5835a 100644 --- a/src/mailman/model/docs/domains.rst +++ b/src/mailman/model/docs/domains.rst @@ -71,6 +71,30 @@ Domains can have explicit descriptions and contact addresses. base_url: http://lists.example.net, contact_address: postmaster@example.com> +Domains can list all associated mailing lists with the mailing_lists property. +:: + + >>> def show_lists(domain): + ... mlists = list(domain.mailing_lists) + ... for mlist in mlists: + ... print mlist + ... if len(mlists) == 0: + ... print 'no lists' + + >>> net_domain = manager['example.net'] + >>> com_domain = manager['example.com'] + >>> show_lists(net_domain) + no lists + + >>> create_list('test@example.net') + <mailing list "test@example.net" at ...> + >>> transaction.commit() + >>> show_lists(net_domain) + <mailing list "test@example.net" at ...> + + >>> show_lists(com_domain) + no lists + In the global domain manager, domains are indexed by their email host name. :: diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index ad3e84fc7..c752d4f0b 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -33,6 +33,7 @@ from mailman.config import config from mailman.database.model import Model from mailman.interfaces.domain import ( BadDomainSpecificationError, IDomain, IDomainManager) +from mailman.model.mailinglist import MailingList @@ -85,6 +86,15 @@ class Domain(Model): """See `IDomain`.""" return urlparse(self.base_url).scheme + @property + def mailing_lists(self): + """See `IDomain`.""" + mailing_lists = config.db.store.find( + MailingList, + MailingList.mail_host == self.mail_host) + for mlist in mailing_lists: + yield mlist + def confirm_url(self, token=''): """See `IDomain`.""" return urljoin(self.base_url, 'confirm/' + token) diff --git a/src/mailman/rest/docs/domains.rst b/src/mailman/rest/docs/domains.rst index 15638c38d..a8a4fd027 100644 --- a/src/mailman/rest/docs/domains.rst +++ b/src/mailman/rest/docs/domains.rst @@ -117,6 +117,40 @@ But we get a 404 for a non-existent domain. ... HTTPError: HTTP Error 404: 404 Not Found +You can also list all the mailing lists for a given domain. At first, the +example.com domain does not contain any mailing lists. +:: + + >>> dump_json('http://localhost:9001/3.0/domains/example.com/lists') + http_etag: "..." + start: 0 + total_size: 0 + + >>> dump_json('http://localhost:9001/3.0/lists', { + ... 'fqdn_listname': 'test-domains@example.com', + ... }) + content-length: 0 + date: ... + location: http://localhost:9001/3.0/lists/test-domains@example.com + ... + + >>> dump_json('http://localhost:9001/3.0/domains/example.com/lists') + entry 0: + fqdn_listname: test-domains@example.com + http_etag: "..." + ... + self_link: http://localhost:9001/3.0/lists/test-domains@example.com + http_etag: "..." + start: 0 + total_size: 1 + +Other domains continue to contain no mailing lists. + + >>> dump_json('http://localhost:9001/3.0/domains/lists.example.net/lists') + http_etag: "..." + start: 0 + total_size: 0 + Creating new domains ==================== diff --git a/src/mailman/rest/docs/lists.rst b/src/mailman/rest/docs/lists.rst index fd96507c3..c412f6edc 100644 --- a/src/mailman/rest/docs/lists.rst +++ b/src/mailman/rest/docs/lists.rst @@ -30,6 +30,26 @@ Create a mailing list in a domain and it's accessible via the API. start: 0 total_size: 1 +You can also query for lists from a particular domain. +:: + + >>> dump_json('http://localhost:9001/3.0/domains/example.com/lists') + entry 0: + fqdn_listname: test-one@example.com + http_etag: "..." + list_name: test-one + mail_host: example.com + real_name: Test-one + self_link: http://localhost:9001/3.0/lists/test-one@example.com + http_etag: "..." + start: 0 + total_size: 1 + + >>> dump_json('http://localhost:9001/3.0/domains/no.example.org/lists') + Traceback (most recent call last): + ... + HTTPError: HTTP Error 404: 404 Not Found + Creating lists via the API ========================== diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py index d42497157..da353ca58 100644 --- a/src/mailman/rest/domains.py +++ b/src/mailman/rest/domains.py @@ -32,6 +32,7 @@ from zope.component import getUtility from mailman.interfaces.domain import ( BadDomainSpecificationError, IDomainManager) from mailman.rest.helpers import CollectionMixin, etag, no_content, path_to +from mailman.rest.lists import ListsForDomain from mailman.rest.validator import Validator @@ -79,6 +80,17 @@ class ADomain(_DomainBase): return http.not_found() return no_content() + @resource.child() + def lists(self, request, segments): + """/domains/<domain>/lists""" + if len(segments) == 0: + domain = getUtility(IDomainManager).get(self._domain) + if domain is None: + return http.not_found() + return ListsForDomain(domain) + else: + return http.bad_request() + class AllDomains(_DomainBase): """The domains.""" diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py index 2c2f58da1..6a6388320 100644 --- a/src/mailman/rest/lists.py +++ b/src/mailman/rest/lists.py @@ -24,6 +24,7 @@ __all__ = [ 'AList', 'AllLists', 'ListConfiguration', + 'ListsForDomain', ] @@ -207,4 +208,20 @@ class MembersOfList(MemberCollection): roster = self._mlist.get_roster(self._role) address_of_member = attrgetter('address.email') return list(sorted(roster.members, key=address_of_member)) - + + +class ListsForDomain(_ListBase): + """The mailing lists for a particular domain.""" + + def __init__(self, domain): + self._domain = domain + + @resource.GET() + def collection(self, request): + """/domains/<domain>/lists""" + resource = self._make_collection(request) + return http.ok([], etag(resource)) + + def _get_collection(self, request): + """See `CollectionMixin`.""" + return list(self._domain.mailing_lists) diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py index cd4c8ceef..dc9717de4 100644 --- a/src/mailman/rest/root.py +++ b/src/mailman/rest/root.py @@ -98,10 +98,9 @@ class TopLevel(resource.Resource): """ if len(segments) == 0: return AllDomains() - elif len(segments) == 1: - return ADomain(segments[0]), [] else: - return http.bad_request() + domain = segments.pop(0) + return ADomain(domain), segments @resource.child() def lists(self, request, segments): diff --git a/src/mailman/rest/tests/test_domains.py b/src/mailman/rest/tests/test_domains.py new file mode 100644 index 000000000..e12d340ae --- /dev/null +++ b/src/mailman/rest/tests/test_domains.py @@ -0,0 +1,72 @@ +# Copyright (C) 2011 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 domain tests.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'test_suite', + ] + + +import unittest + +from urllib2 import HTTPError + +from mailman.app.lifecycle import create_list +from mailman.config import config +from mailman.testing.helpers import call_api +from mailman.testing.layers import RESTLayer + + + +class TestDomains(unittest.TestCase): + layer = RESTLayer + + def setUp(self): + self._mlist = create_list('test@example.com') + config.db.commit() + + def test_bogus_endpoint_extension(self): + # /domains/<domain>/lists/<anything> is not a valid endpoint. + try: + # For Python 2.6. + call_api('http://localhost:9001/3.0/domains/example.com' + '/lists/wrong') + except HTTPError as exc: + self.assertEqual(exc.code, 400) + else: + raise AssertionError('Expected HTTPError') + + def test_bogus_endpoint(self): + # /domains/<domain>/<!lists> does not exist. + try: + # For Python 2.6. + call_api('http://localhost:9001/3.0/domains/example.com/wrong') + except HTTPError as exc: + self.assertEqual(exc.code, 404) + else: + raise AssertionError('Expected HTTPError') + + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestDomains)) + return suite |
