diff --git a/src/postorius/forms.py b/src/postorius/forms.py index 0328936..04d8b40 100644 --- a/src/postorius/forms.py +++ b/src/postorius/forms.py @@ -835,13 +835,6 @@ _('This email is in use. Please choose another or contact' ' the administrator'), 'error') - # Check if the email is attached to a user in Mailman - try: - utils.get_client().get_user(email) - raise forms.ValidationError( - _('This email already belongs to a user'), 'error') - except HTTPError: - pass return email diff --git a/src/postorius/tests/fixtures/vcr_cassettes/TestAddressActivationLinkSuccess.test_existing_user.yaml b/src/postorius/tests/fixtures/vcr_cassettes/TestAddressActivationLinkSuccess.test_existing_user.yaml new file mode 100644 index 0000000..9770489 --- /dev/null +++ b/src/postorius/tests/fixtures/vcr_cassettes/TestAddressActivationLinkSuccess.test_existing_user.yaml @@ -0,0 +1,259 @@ +interactions: +- request: + body: email=ler%40example.org&password=None + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/users + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/users/36'] + status: {code: 201, message: Created} +- request: + body: email=les%40example.org&password=None + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/users + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/users/37'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/ler@example.org + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/36/addresses + response: + body: {string: !!python/unicode '{"entries": [{"email": "ler@example.org", "http_etag": + "\"200edc8cd699f99ec37a93e5ee6001d7a94a934c\"", "original_email": "ler@example.org", + "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/ler@example.org", + "user": "http://localhost:9001/3.0/users/36"}], "http_etag": "\"d4e56c1333a0709562bb8597b88e71706e5a196d\"", + "start": 0, "total_size": 1}'} + headers: + content-length: ['385'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/ler@example.org + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: email=les%40example.org&absorb_existing=1 + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/users/36/addresses + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/addresses/les@example.org'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/addresses/les@example.org/verify + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/ler@example.org + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/36/addresses + response: + body: {string: !!python/unicode '{"entries": [{"email": "ler@example.org", "http_etag": + "\"200edc8cd699f99ec37a93e5ee6001d7a94a934c\"", "original_email": "ler@example.org", + "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/ler@example.org", + "user": "http://localhost:9001/3.0/users/36"}, {"email": "les@example.org", + "http_etag": "\"fb740ff55957047e74c6156941ec9837f60581d1\"", "original_email": + "les@example.org", "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/les@example.org", + "user": "http://localhost:9001/3.0/users/36", "verified_on": "2005-08-01T07:49:23"}], + "http_etag": "\"d8edcc475fdd38e064eaaa0d8aa9a461ccafca36\"", "start": 0, "total_size": + 2}'} + headers: + content-length: ['705'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/ler@example.org + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/36/addresses + response: + body: {string: !!python/unicode '{"entries": [{"email": "ler@example.org", "http_etag": + "\"200edc8cd699f99ec37a93e5ee6001d7a94a934c\"", "original_email": "ler@example.org", + "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/ler@example.org", + "user": "http://localhost:9001/3.0/users/36"}, {"email": "les@example.org", + "http_etag": "\"fb740ff55957047e74c6156941ec9837f60581d1\"", "original_email": + "les@example.org", "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/les@example.org", + "user": "http://localhost:9001/3.0/users/36", "verified_on": "2005-08-01T07:49:23"}], + "http_etag": "\"d8edcc475fdd38e064eaaa0d8aa9a461ccafca36\"", "start": 0, "total_size": + 2}'} + headers: + content-length: ['705'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/ler@example.org + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/36 + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"80be5db66e58bc06266ab6933e273d69ed62a895\"", "is_server_owner": false, + "password": "$6$rounds=712780$M0l.sgxEzkzCeDYD$2LFDRYejEvpjysYXJG6dq5eycN1GUr1lf/pWTiV/jGP77Nc3l2YJQXF40VSUwZf1Nti/o3sianZSyq4rIYSbd/", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}'} + headers: + content-length: ['326'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users/36/addresses + response: + body: {string: !!python/unicode '{"entries": [{"email": "ler@example.org", "http_etag": + "\"200edc8cd699f99ec37a93e5ee6001d7a94a934c\"", "original_email": "ler@example.org", + "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/ler@example.org", + "user": "http://localhost:9001/3.0/users/36"}, {"email": "les@example.org", + "http_etag": "\"fb740ff55957047e74c6156941ec9837f60581d1\"", "original_email": + "les@example.org", "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/les@example.org", + "user": "http://localhost:9001/3.0/users/36", "verified_on": "2005-08-01T07:49:23"}], + "http_etag": "\"d8edcc475fdd38e064eaaa0d8aa9a461ccafca36\"", "start": 0, "total_size": + 2}'} + headers: + content-length: ['705'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains + response: + body: {string: !!python/unicode '{"http_etag": "\"32223434a0f3af4cdc4673d1fbc5bac1f6d98fd3\"", + "start": 0, "total_size": 0}'} + headers: + content-length: ['90'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users + response: + body: {string: !!python/unicode '{"entries": [{"created_on": "2005-08-01T07:49:23", + "http_etag": "\"1c5db752cf25d65b8c5628f240cfc2a77ba33ded\"", "is_server_owner": + false, "password": "$6$rounds=698089$Gt7kUt0Gsn4ZEduV$DQBhVSJMs/yN9VMYJ6GVja11SxdW8bYDya91Xf5C9Le7ejStwuJIdc2.kYsyrJQG09OGw2fnizsKfnEs.9udA1", + "self_link": "http://localhost:9001/3.0/users/36", "user_id": 36}], "http_etag": + "\"a9de2de6a6c0e925565f35e4e5458cd60cdc9826\"", "start": 0, "total_size": + 1}'} + headers: + content-length: ['429'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode DELETE + uri: http://localhost:9001/3.0/users/36 + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +version: 1 diff --git a/src/postorius/tests/mailman_api_tests/test_address_activation.py b/src/postorius/tests/mailman_api_tests/test_address_activation.py index 90c620a..8bd277a 100644 --- a/src/postorius/tests/mailman_api_tests/test_address_activation.py +++ b/src/postorius/tests/mailman_api_tests/test_address_activation.py @@ -64,10 +64,6 @@ form = AddressActivationForm({'email': 'expired@example.org'}) self.assertTrue(form.is_valid()) - def test_email_used_by_mailman_is_invalid(self): - form = AddressActivationForm({'email': 'subscribed@example.org'}) - self.assertFalse(form.is_valid()) - class TestAddressConfirmationProfile(ViewTestCase): """ @@ -173,3 +169,18 @@ set(['ler@example.org', 'les@example.org'])) logged_in_user = response.wsgi_request.user self.assertEqual(logged_in_user.other_emails, ['les@example.org']) + + def test_existing_user(self): + # Add an existing address that is already linked to a user + self.mm_client.create_user("les@example.org", None) + self.client.login(username='ler', password='pwd') + url = reverse('address_activation_link', + args=[self.profile.activation_key]) + response = self.client.get(url) + self.assertRedirects(response, reverse('user_profile')) + self.assertHasSuccessMessage(response) + self.assertEqual( + set([a.email for a in self.mm_user.addresses]), + set(['ler@example.org', 'les@example.org'])) + logged_in_user = response.wsgi_request.user + self.assertEqual(logged_in_user.other_emails, ['les@example.org']) diff --git a/src/postorius/views/user.py b/src/postorius/views/user.py index 887bcf8..bafd778 100644 --- a/src/postorius/views/user.py +++ b/src/postorius/views/user.py @@ -320,9 +320,13 @@ except Mailman404Error: mailman_user = MailmanUser.objects.create( request.user.email, '') - mm_address = mailman_user.add_address(profile.email) + # If the adress already exists, it's an import artefact: it's been + # validated by email, so it's safe to merge. + mm_address = mailman_user.add_address( + profile.email, absorb_existing=True) # The address has just been verified. - mm_address.verify() + if not mm_address.verified_on: + mm_address.verify() except (MailmanApiError, MailmanConnectionError): messages.error(request, _('The address could not be added.')) return