diff --git a/src/postorius/tests/fixtures/vcr_cassettes/TestSubscription.test_mass_subscribe.yaml b/src/postorius/tests/fixtures/vcr_cassettes/TestSubscription.test_mass_subscribe.yaml new file mode 100644 index 0000000..15f3d44 --- /dev/null +++ b/src/postorius/tests/fixtures/vcr_cassettes/TestSubscription.test_mass_subscribe.yaml @@ -0,0 +1,503 @@ +interactions: +- request: + body: mail_host=example.com + 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/domains + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/domains/example.com'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode 'GET' + uri: http://localhost:9001/3.0/domains/example.com + response: + body: {string: !!python/unicode '{"base_url": "http://example.com", "description": + null, "http_etag": "\"e736411818ff1815ca83575e0958c38c5188f0a4\"", "mail_host": + "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com", + "url_host": "example.com"}'} + headers: + content-length: ['233'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: fqdn_listname=open_list%40example.com + 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/lists + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/lists/open_list.example.com'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode 'GET' + uri: http://localhost:9001/3.0/lists/open_list.example.com + response: + body: {string: !!python/unicode '{"display_name": "Open_list", "fqdn_listname": + "open_list@example.com", "http_etag": "\"6726e101e1dd1de6043eee72f741d4c2479f4735\"", + "list_id": "open_list.example.com", "list_name": "open_list", "mail_host": + "example.com", "member_count": 0, "self_link": "http://localhost:9001/3.0/lists/open_list.example.com", + "volume": 1}'} + headers: + content-length: ['324'] + 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/lists/open_list@example.com/config + response: + body: {string: !!python/unicode '{"acceptable_aliases": [], "admin_immed_notify": + true, "admin_notify_mchanges": false, "administrivia": true, "advertised": + true, "allow_list_posts": true, "anonymous_list": false, "archive_policy": + "public", "autorespond_owner": "none", "autorespond_postings": "none", "autorespond_requests": + "none", "autoresponse_grace_period": "90d", "autoresponse_owner_text": "", + "autoresponse_postings_text": "", "autoresponse_request_text": "", "bounces_address": + "open_list-bounces@example.com", "collapse_alternatives": true, "convert_html_to_plaintext": + false, "created_at": "2005-08-01T07:49:23", "default_member_action": "defer", + "default_nonmember_action": "hold", "description": "", "digest_last_sent_at": + null, "digest_send_periodic": true, "digest_size_threshold": 30.0, "digest_volume_frequency": + "monthly", "digests_enabled": true, "display_name": "Open_list", "filter_content": + false, "first_strip_reply_to": false, "fqdn_listname": "open_list@example.com", + "goodbye_message_uri": "", "http_etag": "\"3d16b6c6d1bb8fed130bd061c70a0894856a4ca8\"", + "include_rfc2369_headers": true, "join_address": "open_list-join@example.com", + "last_post_at": null, "leave_address": "open_list-leave@example.com", "list_name": + "open_list", "mail_host": "example.com", "next_digest_number": 1, "no_reply_address": + "noreply@example.com", "owner_address": "open_list-owner@example.com", "post_id": + 1, "posting_address": "open_list@example.com", "posting_pipeline": "default-posting-pipeline", + "reply_goes_to_list": "no_munging", "reply_to_address": "", "request_address": + "open_list-request@example.com", "scheme": "http", "send_welcome_message": + true, "subject_prefix": "[Open_list] ", "subscription_policy": "confirm", + "volume": 1, "web_host": "example.com", "welcome_message_uri": "mailman:///welcome.txt"}'} + headers: + content-length: ['1790'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: subscription_policy=open + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode 'content-type': [!!python/unicode 'application/x-www-form-urlencoded'] + method: !!python/unicode 'PATCH' + uri: http://localhost:9001/3.0/lists/open_list@example.com/config + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: fqdn_listname=moderate_subs%40example.com + 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/lists + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/lists/moderate_subs.example.com'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode 'GET' + uri: http://localhost:9001/3.0/lists/moderate_subs.example.com + response: + body: {string: !!python/unicode '{"display_name": "Moderate_subs", "fqdn_listname": + "moderate_subs@example.com", "http_etag": "\"4cf5a031a451ad84a54e4c708cacda8e676e617f\"", + "list_id": "moderate_subs.example.com", "list_name": "moderate_subs", "mail_host": + "example.com", "member_count": 0, "self_link": "http://localhost:9001/3.0/lists/moderate_subs.example.com", + "volume": 1}'} + headers: + content-length: ['344'] + 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/lists/moderate_subs@example.com/config + response: + body: {string: !!python/unicode '{"acceptable_aliases": [], "admin_immed_notify": + true, "admin_notify_mchanges": false, "administrivia": true, "advertised": + true, "allow_list_posts": true, "anonymous_list": false, "archive_policy": + "public", "autorespond_owner": "none", "autorespond_postings": "none", "autorespond_requests": + "none", "autoresponse_grace_period": "90d", "autoresponse_owner_text": "", + "autoresponse_postings_text": "", "autoresponse_request_text": "", "bounces_address": + "moderate_subs-bounces@example.com", "collapse_alternatives": true, "convert_html_to_plaintext": + false, "created_at": "2005-08-01T07:49:23", "default_member_action": "defer", + "default_nonmember_action": "hold", "description": "", "digest_last_sent_at": + null, "digest_send_periodic": true, "digest_size_threshold": 30.0, "digest_volume_frequency": + "monthly", "digests_enabled": true, "display_name": "Moderate_subs", "filter_content": + false, "first_strip_reply_to": false, "fqdn_listname": "moderate_subs@example.com", + "goodbye_message_uri": "", "http_etag": "\"bbeb372001a49a25fa038477abd59e8b3c45a20d\"", + "include_rfc2369_headers": true, "join_address": "moderate_subs-join@example.com", + "last_post_at": null, "leave_address": "moderate_subs-leave@example.com", + "list_name": "moderate_subs", "mail_host": "example.com", "next_digest_number": + 1, "no_reply_address": "noreply@example.com", "owner_address": "moderate_subs-owner@example.com", + "post_id": 1, "posting_address": "moderate_subs@example.com", "posting_pipeline": + "default-posting-pipeline", "reply_goes_to_list": "no_munging", "reply_to_address": + "", "request_address": "moderate_subs-request@example.com", "scheme": "http", + "send_welcome_message": true, "subject_prefix": "[Moderate_subs] ", "subscription_policy": + "confirm", "volume": 1, "web_host": "example.com", "welcome_message_uri": + "mailman:///welcome.txt"}'} + headers: + content-length: ['1830'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: subscription_policy=moderate + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode 'content-type': [!!python/unicode 'application/x-www-form-urlencoded'] + method: !!python/unicode 'PATCH' + uri: http://localhost:9001/3.0/lists/moderate_subs@example.com/config + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: email=test%40example.com + 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/791'] + status: {code: 201, message: Created} +- request: + body: email=fritz%40example.org + 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/791/addresses + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/addresses/fritz@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/fritz@example.org/verify + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: list_id=open_list.example.com&role=owner&subscriber=owner%40example.com + 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/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/members/1883'] + status: {code: 201, message: Created} +- request: + body: email=kane%40example.org + 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/791/addresses + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/addresses/kane@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/kane@example.org/verify + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: email=abel%40example.org + 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/791/addresses + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/addresses/abel@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/abel@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/owner@example.com + response: + body: {string: !!python/unicode '{"created_on": "2005-08-01T07:49:23", "http_etag": + "\"978a716bd2fdac7229a2329c84719c4769432b23\"", "is_server_owner": false, + "self_link": "http://localhost:9001/3.0/users/792", "user_id": 792}'} + headers: + content-length: ['192'] + 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/792/addresses + response: + body: {string: !!python/unicode '{"entries": [{"email": "owner@example.com", "http_etag": + "\"ec2d8ce39b559903cb77a9600492b90dd6cf9940\"", "original_email": "owner@example.com", + "registered_on": "2005-08-01T07:49:23", "self_link": "http://localhost:9001/3.0/addresses/owner@example.com", + "user": "http://localhost:9001/3.0/users/792"}], "http_etag": "\"9d73963e544313d8f078e8ee6a2247b167917a1d\"", + "start": 0, "total_size": 1}'} + headers: + content-length: ['392'] + 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/lists/open_list.example.com + response: + body: {string: !!python/unicode '{"display_name": "Open_list", "fqdn_listname": + "open_list@example.com", "http_etag": "\"6726e101e1dd1de6043eee72f741d4c2479f4735\"", + "list_id": "open_list.example.com", "list_name": "open_list", "mail_host": + "example.com", "member_count": 0, "self_link": "http://localhost:9001/3.0/lists/open_list.example.com", + "volume": 1}'} + headers: + content-length: ['324'] + 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/lists/open_list.example.com/roster/owner + response: + body: {string: !!python/unicode '{"entries": [{"address": "http://localhost:9001/3.0/addresses/owner@example.com", + "delivery_mode": "regular", "email": "owner@example.com", "http_etag": "\"1a781e5fbe7a28e4407456543e901f412e3be73b\"", + "list_id": "open_list.example.com", "member_id": 1883, "moderation_action": + "accept", "role": "owner", "self_link": "http://localhost:9001/3.0/members/1883", + "user": "http://localhost:9001/3.0/users/792"}], "http_etag": "\"7f7c9dc5a21641766165f90eab2628e0370da4dc\"", + "start": 0, "total_size": 1}'} + headers: + content-length: ['497'] + 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/lists/open_list.example.com/roster/moderator + 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/lists/open_list.example.com + response: + body: {string: !!python/unicode '{"display_name": "Open_list", "fqdn_listname": + "open_list@example.com", "http_etag": "\"6726e101e1dd1de6043eee72f741d4c2479f4735\"", + "list_id": "open_list.example.com", "list_name": "open_list", "mail_host": + "example.com", "member_count": 0, "self_link": "http://localhost:9001/3.0/lists/open_list.example.com", + "volume": 1}'} + headers: + content-length: ['324'] + content-type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: display_name=None&list_id=open_list.example.com&pre_approved=True&pre_confirmed=True&pre_verified=True&subscriber=fritz%40example.org + 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/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/members/1884'] + status: {code: 201, message: Created} +- request: + body: display_name=None&list_id=open_list.example.com&pre_approved=True&pre_confirmed=True&pre_verified=True&subscriber=kane%40example.org + 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/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/members/1885'] + status: {code: 201, message: Created} +- request: + body: display_name=None&list_id=open_list.example.com&pre_approved=True&pre_confirmed=True&pre_verified=True&subscriber=abel%40example.org + 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/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + location: ['http://localhost:9001/3.0/members/1886'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode 'GET' + uri: http://localhost:9001/3.0/lists/open_list@example.com/roster/member + response: + body: {string: !!python/unicode '{"entries": [{"address": "http://localhost:9001/3.0/addresses/abel@example.org", + "delivery_mode": "regular", "email": "abel@example.org", "http_etag": "\"32b53ad20fd1050b506aaa008b835bb1ca32c8d8\"", + "list_id": "open_list.example.com", "member_id": 1886, "moderation_action": + "defer", "role": "member", "self_link": "http://localhost:9001/3.0/members/1886", + "user": "http://localhost:9001/3.0/users/791"}, {"address": "http://localhost:9001/3.0/addresses/fritz@example.org", + "delivery_mode": "regular", "email": "fritz@example.org", "http_etag": "\"d33df8ac567381bfed477f4f3b15d80c2c8eb8c1\"", + "list_id": "open_list.example.com", "member_id": 1884, "moderation_action": + "defer", "role": "member", "self_link": "http://localhost:9001/3.0/members/1884", + "user": "http://localhost:9001/3.0/users/791"}, {"address": "http://localhost:9001/3.0/addresses/kane@example.org", + "delivery_mode": "regular", "email": "kane@example.org", "http_etag": "\"041a929cb61734f97828432909ad8f8119bbd8ad\"", + "list_id": "open_list.example.com", "member_id": 1885, "moderation_action": + "defer", "role": "member", "self_link": "http://localhost:9001/3.0/members/1885", + "user": "http://localhost:9001/3.0/users/791"}], "http_etag": "\"768c084d3fb6679403e28163b532167d3ad8125c\"", + "start": 0, "total_size": 3}'} + headers: + content-length: ['1281'] + 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/lists/open_list@example.com/requests + 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/lists/moderate_subs@example.com/requests + 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 'DELETE' + uri: http://localhost:9001/3.0/lists/open_list@example.com + 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 'DELETE' + uri: http://localhost:9001/3.0/lists/moderate_subs@example.com + 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 'DELETE' + uri: http://localhost:9001/3.0/users/791 + 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 'DELETE' + uri: http://localhost:9001/3.0/domains/example.com + 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_subscriptions.py b/src/postorius/tests/mailman_api_tests/test_subscriptions.py index a3bce6d..2f226ed 100644 --- a/src/postorius/tests/mailman_api_tests/test_subscriptions.py +++ b/src/postorius/tests/mailman_api_tests/test_subscriptions.py @@ -154,3 +154,14 @@ args=['moderate_subs.example.com'])) message = self.assertHasSuccessMessage(response) self.assertIn('Already subscribed', message) + + def test_mass_subscribe(self): + # Perform mass subscription + User.objects.create_user('testowner', 'owner@example.com', 'pwd') + self.open_list.add_owner('owner@example.com') + self.client.login(username='testowner', password='pwd') + email_list = 'fritz@example.org\nkane@example.org\nabel@example.org\n' + response = self.client.post( + reverse('mass_subscribe', args=('open_list.example.com',)), + {'emails': email_list}) + self.assertEqual(len(self.open_list.members), 3) diff --git a/src/postorius/views/list.py b/src/postorius/views/list.py index 989c6b1..fc8311d 100644 --- a/src/postorius/views/list.py +++ b/src/postorius/views/list.py @@ -24,6 +24,7 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, user_passes_test from django.core.urlresolvers import reverse +from django.core.validators import validate_email from django.forms import formset_factory from django.shortcuts import render, redirect from django.template import RequestContext