diff options
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 6 | ||||
| -rw-r--r-- | src/mailman/rest/docs/users.rst | 32 | ||||
| -rw-r--r-- | src/mailman/rest/tests/test_users.py | 37 | ||||
| -rw-r--r-- | src/mailman/rest/users.py | 19 |
4 files changed, 88 insertions, 6 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index 95663d5ee..0000afb73 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -22,6 +22,12 @@ Configuration * The default languages from Mailman 2.1 have been ported over. Given by Aurélien Bompard. +REST +---- + * When creating a user via REST using an address that already exists, but + isn't linked, the address is linked to the new user. Given by Aurélien + Bompard. + 3.0.0 -- "Show Don't Tell" ========================== diff --git a/src/mailman/rest/docs/users.rst b/src/mailman/rest/docs/users.rst index 13390a00f..493cf65e2 100644 --- a/src/mailman/rest/docs/users.rst +++ b/src/mailman/rest/docs/users.rst @@ -496,3 +496,35 @@ Gwen, a new users, takes over as a server owner. password: {plaintext}... self_link: http://localhost:9001/3.0/users/7 user_id: 7 + + +Linking users +============= + +If an address already exists, but is not yet linked to a user, and a new user +is requested for that address, the user will be linked to the existing +address. + +Herb's address already exists, but no user is linked to it. + + >>> herb = user_manager.create_address('herb@example.com') + >>> print(herb.user) + None + >>> transaction.commit() + +Now, a user creation request is received, using Herb's email address. + + >>> dump_json('http://localhost:9001/3.0/users', { + ... 'email': 'herb@example.com', + ... 'display_name': 'Herb Person', + ... }) + content-length: 0 + date: ... + location: http://localhost:9001/3.0/users/8 + server: ... + status: 201 + +Herb's email address is now linked to the new user. + + >>> herb.user + <User "Herb Person" (8) at ... diff --git a/src/mailman/rest/tests/test_users.py b/src/mailman/rest/tests/test_users.py index ac8d018e8..d58d7f9c3 100644 --- a/src/mailman/rest/tests/test_users.py +++ b/src/mailman/rest/tests/test_users.py @@ -160,7 +160,7 @@ class TestUsers(unittest.TestCase): }) self.assertEqual(cm.exception.code, 400) self.assertEqual(cm.exception.reason, - b'Address already exists: anne@example.com') + b'User already exists: anne@example.com') def test_addresses_of_missing_user_id(self): # Trying to get the /addresses of a missing user id results in error. @@ -190,6 +190,39 @@ class TestUsers(unittest.TestCase): }) self.assertEqual(cm.exception.code, 404) + def test_existing_address_link(self): + # Creating a user with an existing address links them. + user_manager = getUtility(IUserManager) + with transaction(): + user_manager.create_address('anne@example.com') + call_api('http://localhost:9001/3.0/users', dict( + email='anne@example.com', + )) + anne = user_manager.get_user('anne@example.com') + self.assertEqual(anne.display_name, '') + self.assertFalse(anne.is_server_owner) + self.assertIn('anne@example.com', + [address.email for address in anne.addresses]) + + def test_existing_address_link_with_arguments(self): + # Creating a user with an existing address links them, and the + # addition arguments get honored. + user_manager = getUtility(IUserManager) + with transaction(): + user_manager.create_address('anne@example.com') + call_api('http://localhost:9001/3.0/users', dict( + email='anne@example.com', + display_name='Anne Person', + password='123', + is_server_owner=True, + )) + anne = user_manager.get_user('anne@example.com') + self.assertEqual(anne.display_name, 'Anne Person') + self.assertTrue(anne.is_server_owner) + self.assertEqual(anne.password, '{plaintext}123') + self.assertIn('anne@example.com', + [address.email for address in anne.addresses]) + def test_create_user_twice(self): # LP: #1418280. No additional users should be created when an address # that already exists is given. @@ -207,7 +240,7 @@ class TestUsers(unittest.TestCase): email='anne@example.com')) self.assertEqual(cm.exception.code, 400) self.assertEqual(cm.exception.reason, - b'Address already exists: anne@example.com') + b'User already exists: anne@example.com') # But at least no new users was created. content, response = call_api('http://localhost:9001/3.0/users') self.assertEqual(content['total_size'], 1) diff --git a/src/mailman/rest/users.py b/src/mailman/rest/users.py index 7b1ec8040..4521593d4 100644 --- a/src/mailman/rest/users.py +++ b/src/mailman/rest/users.py @@ -96,12 +96,23 @@ def create_user(arguments, response): # after the fact if successful. password = arguments.pop('password', None) is_server_owner = arguments.pop('is_server_owner', False) + user_manager = getUtility(IUserManager) try: - user = getUtility(IUserManager).create_user(**arguments) + user = user_manager.create_user(**arguments) except ExistingAddressError as error: - bad_request( - response, 'Address already exists: {}'.format(error.address)) - return None + # The address already exists. If the address already has a user + # linked to it, raise an error, otherwise create a new user and link + # it to this address. + email = arguments.pop('email') + user = user_manager.get_user(email) + if user is None: + address = user_manager.get_address(email) + user = user_manager.create_user(**arguments) + user.link(address) + else: + bad_request( + response, 'User already exists: {}'.format(error.address)) + return None if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) |
