diff options
| author | Barry Warsaw | 2014-04-15 17:54:35 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2014-04-15 17:54:35 -0400 |
| commit | 13823e4d2b9bea190dd207a02a8107bc43ee49fe (patch) | |
| tree | 0917bab22a2d9d422567c80d2c27a4e601103ea2 /src | |
| parent | 29d6d587389c32eb84d7faa51e3072e02e385c2d (diff) | |
| download | mailman-13823e4d2b9bea190dd207a02a8107bc43ee49fe.tar.gz mailman-13823e4d2b9bea190dd207a02a8107bc43ee49fe.tar.zst mailman-13823e4d2b9bea190dd207a02a8107bc43ee49fe.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 6 | ||||
| -rw-r--r-- | src/mailman/rest/docs/addresses.rst | 15 | ||||
| -rw-r--r-- | src/mailman/rest/docs/membership.rst | 138 | ||||
| -rw-r--r-- | src/mailman/rest/members.py | 23 | ||||
| -rw-r--r-- | src/mailman/rest/tests/test_membership.py | 129 | ||||
| -rw-r--r-- | src/mailman/rest/tests/test_users.py | 5 |
6 files changed, 251 insertions, 65 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index f41542a22..0e9a8b875 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -33,6 +33,12 @@ REST site-wide. [Joanna Skrzeszewska] (LP: #1158040) * Addresses can be added to existing users, including display names, via the REST API. [Florian Fuchs] + * Fixed a crash in the REST server when searching for nonmembers via + ``/find`` which we've never seen before, because those members only have an + address record, not a user record. This requires a small change in the API + where the JSON response's ``address`` key now contains the URL to the + address resource, the new ``email`` key contains the email address as a + string, and the ``user`` key is optional. Commands -------- diff --git a/src/mailman/rest/docs/addresses.rst b/src/mailman/rest/docs/addresses.rst index be01dd623..fec0c194b 100644 --- a/src/mailman/rest/docs/addresses.rst +++ b/src/mailman/rest/docs/addresses.rst @@ -261,16 +261,18 @@ Elle can get her memberships for each of her email addresses. >>> dump_json('http://localhost:9001/3.0/addresses/' ... 'elle@example.com/memberships') entry 0: - address: elle@example.com + address: http://localhost:9001/3.0/addresses/elle@example.com delivery_mode: regular + email: elle@example.com http_etag: "..." list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/2 entry 1: - address: elle@example.com + address: http://localhost:9001/3.0/addresses/elle@example.com delivery_mode: regular + email: elle@example.com http_etag: "..." list_id: bee.example.com role: member @@ -298,16 +300,18 @@ does not show up in the list of memberships for his other address. >>> dump_json('http://localhost:9001/3.0/addresses/' ... 'elle@example.com/memberships') entry 0: - address: elle@example.com + address: http://localhost:9001/3.0/addresses/elle@example.com delivery_mode: regular + email: elle@example.com http_etag: "..." list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/2 entry 1: - address: elle@example.com + address: http://localhost:9001/3.0/addresses/elle@example.com delivery_mode: regular + email: elle@example.com http_etag: "..." list_id: bee.example.com role: member @@ -320,8 +324,9 @@ does not show up in the list of memberships for his other address. >>> dump_json('http://localhost:9001/3.0/addresses/' ... 'eperson@example.com/memberships') entry 0: - address: eperson@example.com + address: http://localhost:9001/3.0/addresses/eperson@example.com delivery_mode: regular + email: eperson@example.com http_etag: "..." list_id: bee.example.com role: member diff --git a/src/mailman/rest/docs/membership.rst b/src/mailman/rest/docs/membership.rst index 10fd4732e..7c92d8343 100644 --- a/src/mailman/rest/docs/membership.rst +++ b/src/mailman/rest/docs/membership.rst @@ -41,8 +41,9 @@ the REST interface. >>> subscribe(bee, 'Bart') >>> dump_json('http://localhost:9001/3.0/members') entry 0: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -55,8 +56,9 @@ the REST interface. Bart's specific membership can be accessed directly: >>> dump_json('http://localhost:9001/3.0/members/1') - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -69,16 +71,18 @@ the REST interface. >>> subscribe(bee, 'Cris') >>> dump_json('http://localhost:9001/3.0/members') entry 0: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/1 entry 1: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -96,24 +100,27 @@ subscribes, she is returned first. >>> dump_json('http://localhost:9001/3.0/members') entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/3 user: http://localhost:9001/3.0/users/3 entry 1: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/1 entry 2: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -135,40 +142,45 @@ User ids are different than member ids. >>> dump_json('http://localhost:9001/3.0/members') entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/4 user: http://localhost:9001/3.0/users/3 entry 1: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/5 user: http://localhost:9001/3.0/users/2 entry 2: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/3 user: http://localhost:9001/3.0/users/3 entry 3: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/1 entry 4: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -183,16 +195,18 @@ We can also get just the members of a single mailing list. >>> dump_json( ... 'http://localhost:9001/3.0/lists/ant@example.com/roster/member') entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/4 user: http://localhost:9001/3.0/users/3 entry 1: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: ant.example.com role: member @@ -215,8 +229,9 @@ page. ... 'http://localhost:9001/3.0/lists/ant@example.com/roster/member' ... '?count=1&page=1') entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member @@ -231,8 +246,9 @@ This works with members of a single list as well as with all members. >>> dump_json( ... 'http://localhost:9001/3.0/members?count=1&page=1') entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member @@ -275,56 +291,63 @@ mailing list. >>> dump_json('http://localhost:9001/3.0/members') entry 0: - address: dperson@example.com + address: http://localhost:9001/3.0/addresses/dperson@example.com delivery_mode: regular + email: dperson@example.com http_etag: ... list_id: ant.example.com role: moderator self_link: http://localhost:9001/3.0/members/6 user: http://localhost:9001/3.0/users/4 entry 1: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/4 user: http://localhost:9001/3.0/users/3 entry 2: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/5 user: http://localhost:9001/3.0/users/2 entry 3: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: owner self_link: http://localhost:9001/3.0/members/7 user: http://localhost:9001/3.0/users/2 entry 4: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/3 user: http://localhost:9001/3.0/users/3 entry 5: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/1 entry 6: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -339,8 +362,9 @@ We can access all the owners of a list. >>> dump_json( ... 'http://localhost:9001/3.0/lists/bee@example.com/roster/owner') entry 0: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: owner @@ -358,8 +382,9 @@ A specific member can always be referenced by their role and address. >>> dump_json('http://localhost:9001/3.0/lists/' ... 'bee@example.com/owner/cperson@example.com') - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: owner @@ -373,16 +398,18 @@ example, we can search for all the memberships of a particular address. ... 'subscriber': 'aperson@example.com', ... }) entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/4 user: http://localhost:9001/3.0/users/3 entry 1: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -398,32 +425,36 @@ Or, we can find all the memberships for a particular mailing list. ... 'list_id': 'bee.example.com', ... }) entry 0: - address: aperson@example.com + address: http://localhost:9001/3.0/addresses/aperson@example.com delivery_mode: regular + email: aperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/3 user: http://localhost:9001/3.0/users/3 entry 1: - address: bperson@example.com + address: http://localhost:9001/3.0/addresses/bperson@example.com delivery_mode: regular + email: bperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/1 user: http://localhost:9001/3.0/users/1 entry 2: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/2 user: http://localhost:9001/3.0/users/2 entry 3: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: owner @@ -441,16 +472,18 @@ list. ... 'list_id': 'bee.example.com', ... }) entry 0: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member self_link: http://localhost:9001/3.0/members/2 user: http://localhost:9001/3.0/users/2 entry 1: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: owner @@ -467,16 +500,18 @@ Or, we can find all the memberships for an address with a specific role. ... 'role': 'member', ... }) entry 0: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/5 user: http://localhost:9001/3.0/users/2 entry 1: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -494,8 +529,9 @@ Finally, we can search for a specific member given all three criteria. ... 'role': 'member', ... }) entry 0: - address: cperson@example.com + address: http://localhost:9001/3.0/addresses/cperson@example.com delivery_mode: regular + email: cperson@example.com http_etag: ... list_id: bee.example.com role: member @@ -542,8 +578,9 @@ Elly is now a known user, and a member of the mailing list. entry 0: ... entry 3: - address: eperson@example.com + address: http://localhost:9001/3.0/addresses/eperson@example.com delivery_mode: regular + email: eperson@example.com http_etag: ... list_id: ant.example.com role: member @@ -583,8 +620,9 @@ list with her preferred address. entry 0: ... entry 4: - address: gwen@example.com + address: http://localhost:9001/3.0/addresses/gwen@example.com delivery_mode: regular + email: gwen@example.com http_etag: "..." list_id: ant.example.com role: member @@ -606,8 +644,9 @@ the new address. entry 0: ... entry 4: - address: gwen.person@example.com + address: http://localhost:9001/3.0/addresses/gwen.person@example.com delivery_mode: regular + email: gwen.person@example.com http_etag: "..." list_id: ant.example.com role: member @@ -671,8 +710,9 @@ Fred is getting MIME deliveries. DeliveryMode.mime_digests >>> dump_json('http://localhost:9001/3.0/members/10') - address: fperson@example.com + address: http://localhost:9001/3.0/addresses/fperson@example.com delivery_mode: mime_digests + email: fperson@example.com http_etag: "..." list_id: ant.example.com role: member @@ -693,8 +733,9 @@ This can be done by PATCH'ing his member with the `delivery_mode` parameter. status: 204 >>> dump_json('http://localhost:9001/3.0/members/10') - address: fperson@example.com + address: http://localhost:9001/3.0/addresses/fperson@example.com delivery_mode: regular + email: fperson@example.com http_etag: "..." list_id: ant.example.com role: member @@ -711,8 +752,9 @@ If a PATCH request changes no attributes, nothing happens. status: 204 >>> dump_json('http://localhost:9001/3.0/members/10') - address: fperson@example.com + address: http://localhost:9001/3.0/addresses/fperson@example.com delivery_mode: regular + email: fperson@example.com http_etag: "..." list_id: ant.example.com role: member @@ -753,8 +795,9 @@ addresses. entry 0: ... entry 5: - address: herb@example.com + address: http://localhost:9001/3.0/addresses/herb@example.com delivery_mode: regular + email: herb@example.com http_etag: "..." list_id: ant.example.com role: member @@ -762,8 +805,9 @@ addresses. user: http://localhost:9001/3.0/users/8 ... entry 10: - address: herb@example.com + address: http://localhost:9001/3.0/addresses/herb@example.com delivery_mode: regular + email: herb@example.com http_etag: "..." list_id: bee.example.com role: member @@ -818,16 +862,18 @@ his membership ids have not changed. >>> dump_json('http://localhost:9001/3.0/addresses/' ... 'hperson@example.com/memberships') entry 0: - address: hperson@example.com + address: http://localhost:9001/3.0/addresses/hperson@example.com delivery_mode: regular + email: hperson@example.com http_etag: "..." list_id: ant.example.com role: member self_link: http://localhost:9001/3.0/members/11 user: http://localhost:9001/3.0/users/8 entry 1: - address: hperson@example.com + address: http://localhost:9001/3.0/addresses/hperson@example.com delivery_mode: regular + email: hperson@example.com http_etag: "..." list_id: bee.example.com role: member diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py index 5be7a4525..4aef93e34 100644 --- a/src/mailman/rest/members.py +++ b/src/mailman/rest/members.py @@ -56,18 +56,25 @@ class _MemberBase(resource.Resource, CollectionMixin): def _resource_as_dict(self, member): """See `CollectionMixin`.""" enum, dot, role = str(member.role).partition('.') - # Both the user_id and the member_id are UUIDs. We need to use the - # integer equivalent in the URL. - user_id = member.user.user_id.int - member_id = member.member_id.int - return dict( + # The member will always have a member id and an address id. It will + # only have a user id if the address is linked to a user. + # E.g. nonmembers we've only seen via postings to lists they are not + # subscribed to will not have a user id. The user_id and the + # member_id are UUIDs. We need to use the integer equivalent in the + # URL. + response = dict( list_id=member.list_id, - address=member.address.email, + email=member.address.email, role=role, - user=path_to('users/{0}'.format(user_id)), - self_link=path_to('members/{0}'.format(member_id)), + address=path_to('addresses/{}'.format(member.address.email)), + self_link=path_to('members/{}'.format(member.member_id.int)), delivery_mode=member.delivery_mode, ) + # Add the user link if there is one. + user = member.user + if user is not None: + response['user'] = path_to('users/{}'.format(user.user_id.int)) + return response @paginate def _get_collection(self, request): diff --git a/src/mailman/rest/tests/test_membership.py b/src/mailman/rest/tests/test_membership.py index 037ef36b0..503d68a94 100644 --- a/src/mailman/rest/tests/test_membership.py +++ b/src/mailman/rest/tests/test_membership.py @@ -22,6 +22,7 @@ from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'TestMembership', + 'TestNonmembership', ] @@ -34,8 +35,11 @@ from mailman.app.lifecycle import create_list from mailman.config import config from mailman.database.transaction import transaction from mailman.interfaces.usermanager import IUserManager -from mailman.testing.helpers import call_api -from mailman.testing.layers import RESTLayer +from mailman.testing.helpers import ( + TestableMaster, call_api, get_lmtp_client, make_testable_runner, + wait_for_webservice) +from mailman.runners.incoming import IncomingRunner +from mailman.testing.layers import ConfigLayer, RESTLayer from mailman.utilities.datetime import now @@ -144,7 +148,10 @@ class TestMembership(unittest.TestCase): 'http://localhost:9001/3.0/members/1') self.assertEqual(entry_0['role'], 'member') self.assertEqual(entry_0['user'], 'http://localhost:9001/3.0/users/1') - self.assertEqual(entry_0['address'], 'anne@example.com') + self.assertEqual(entry_0['email'], 'anne@example.com') + self.assertEqual( + entry_0['address'], + 'http://localhost:9001/3.0/addresses/anne@example.com') self.assertEqual(entry_0['list_id'], 'test.example.com') def test_member_changes_preferred_address(self): @@ -158,7 +165,10 @@ class TestMembership(unittest.TestCase): content, response = call_api('http://localhost:9001/3.0/members') self.assertEqual(int(content['total_size']), 1) entry_0 = content['entries'][0] - self.assertEqual(entry_0['address'], 'anne@example.com') + self.assertEqual(entry_0['email'], 'anne@example.com') + self.assertEqual( + entry_0['address'], + 'http://localhost:9001/3.0/addresses/anne@example.com') # Anne registers a new address and makes it her preferred address. # There are no changes to her membership. with transaction(): @@ -169,7 +179,10 @@ class TestMembership(unittest.TestCase): content, response = call_api('http://localhost:9001/3.0/members') self.assertEqual(int(content['total_size']), 1) entry_0 = content['entries'][0] - self.assertEqual(entry_0['address'], 'aperson@example.com') + self.assertEqual(entry_0['email'], 'aperson@example.com') + self.assertEqual( + entry_0['address'], + 'http://localhost:9001/3.0/addresses/aperson@example.com') def test_get_nonexistent_member(self): # /members/<bogus> returns 404 @@ -202,3 +215,109 @@ class TestMembership(unittest.TestCase): with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/1/all') self.assertEqual(cm.exception.code, 404) + + + +class CustomLayer(ConfigLayer): + """Custom layer which starts both the REST and LMTP servers.""" + + server = None + client = None + + @classmethod + def _wait_for_both(cls): + cls.client = get_lmtp_client(quiet=True) + wait_for_webservice() + + @classmethod + def setUp(cls): + assert cls.server is None, 'Layer already set up' + cls.server = TestableMaster(cls._wait_for_both) + cls.server.start('lmtp', 'rest') + + @classmethod + def tearDown(cls): + assert cls.server is not None, 'Layer is not set up' + cls.server.stop() + cls.server = None + + +class TestNonmembership(unittest.TestCase): + layer = CustomLayer + + def setUp(self): + with transaction(): + self._mlist = create_list('test@example.com') + self._usermanager = getUtility(IUserManager) + + def _go(self, message): + lmtp = get_lmtp_client(quiet=True) + lmtp.lhlo('remote.example.org') + lmtp.sendmail('nonmember@example.com', ['test@example.com'], message) + lmtp.close() + # The message will now be sitting in the `in` queue. Run the incoming + # runner once to process it, which should result in the nonmember + # showing up. + inq = make_testable_runner(IncomingRunner, 'in') + inq.run() + + def test_nonmember_findable_after_posting(self): + # A nonmember we have never seen before posts a message to the mailing + # list. They are findable through the /members/find API using a role + # of nonmember. + self._go("""\ +From: nonmember@example.com +To: test@example.com +Subject: Nonmember post +Message-ID: <alpha> + +Some text. +""") + # Now use the REST API to try to find the nonmember. + response, content = call_api( + 'http://localhost:9001/3.0/members/find', { + #'list_id': 'test.example.com', + 'role': 'nonmember', + }) + self.assertEqual(response['total_size'], 1) + nonmember = response['entries'][0] + self.assertEqual(nonmember['role'], 'nonmember') + self.assertEqual(nonmember['email'], 'nonmember@example.com') + self.assertEqual( + nonmember['address'], + 'http://localhost:9001/3.0/addresses/nonmember@example.com') + # There is no user key in the JSON data because there is no user + # record associated with the address record. + self.assertNotIn('user', nonmember) + + def test_linked_nonmember_findable_after_posting(self): + # Like above, a nonmember posts a message to the mailing list. In + # this case though, the nonmember already has a user record. They are + # findable through the /members/find API using a role of nonmember. + with transaction(): + self._usermanager.create_user('nonmember@example.com') + self._go("""\ +From: nonmember@example.com +To: test@example.com +Subject: Nonmember post +Message-ID: <alpha> + +Some text. +""") + # Now use the REST API to try to find the nonmember. + response, content = call_api( + 'http://localhost:9001/3.0/members/find', { + #'list_id': 'test.example.com', + 'role': 'nonmember', + }) + self.assertEqual(response['total_size'], 1) + nonmember = response['entries'][0] + self.assertEqual(nonmember['role'], 'nonmember') + self.assertEqual(nonmember['email'], 'nonmember@example.com') + self.assertEqual( + nonmember['address'], + 'http://localhost:9001/3.0/addresses/nonmember@example.com') + # There is a user key in the JSON data because the address had + # previously been linked to a user record. + self.assertEqual(nonmember['user'], + 'http://localhost:9001/3.0/users/1') diff --git a/src/mailman/rest/tests/test_users.py b/src/mailman/rest/tests/test_users.py index 80bf9526d..10cc724a3 100644 --- a/src/mailman/rest/tests/test_users.py +++ b/src/mailman/rest/tests/test_users.py @@ -229,7 +229,10 @@ class TestLP1074374(unittest.TestCase): content, response = call_api('http://localhost:9001/3.0/members') self.assertEqual(content['total_size'], 1) member = content['entries'][0] - self.assertEqual(member['address'], 'anne@example.com') + self.assertEqual( + member['address'], + 'http://localhost:9001/3.0/addresses/anne@example.com') + self.assertEqual(member['email'], 'anne@example.com') self.assertEqual(member['delivery_mode'], 'regular') self.assertEqual(member['list_id'], 'test.example.com') self.assertEqual(member['role'], 'member') |
