Exemple #1
0
 def test_email_only(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     result = self._command.invoke(members, (
         '--email-only', 'ant.example.com'))
     self.assertEqual(
         result.output, '[email protected]\[email protected]\n')
Exemple #2
0
 def test_no_welcome_message_to_moderators(self):
     # Welcome messages go only to mailing list members, not to moderators.
     subscribe(self._mlist, 'Anne', MemberRole.moderator,
               '*****@*****.**')
     # There is no welcome message in the virgin queue.
     messages = get_queue_messages('virgin')
     self.assertEqual(len(messages), 0)
Exemple #3
0
 def test_bad_preferences_url(self):
     with transaction():
         subscribe(self._mlist, 'Anne')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com/preferences/bogus')
     self.assertEqual(cm.exception.code, 404)
Exemple #4
0
 def test_bad_preferences_url(self):
     with transaction():
         subscribe(self._mlist, 'Anne')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com/preferences/bogus')
     self.assertEqual(cm.exception.code, 404)
Exemple #5
0
 def test_member_ids_are_hex(self):
     with transaction():
         subscribe(self._mlist, 'Anne')
         subscribe(self._mlist, 'Bart')
     json, response = call_api('http://localhost:9001/3.1/members')
     entries = json['entries']
     self.assertEqual(len(entries), 2)
     self.assertEqual(
         entries[0]['self_link'],
         'http://localhost:9001/3.1/members/00000000000000000000000000000001'
     )
     self.assertEqual(entries[0]['member_id'],
                      '00000000000000000000000000000001')
     self.assertEqual(
         entries[0]['user'],
         'http://localhost:9001/3.1/users/00000000000000000000000000000001')
     self.assertEqual(
         entries[1]['self_link'],
         'http://localhost:9001/3.1/members/00000000000000000000000000000002'
     )
     self.assertEqual(entries[1]['member_id'],
                      '00000000000000000000000000000002')
     self.assertEqual(
         entries[1]['user'],
         'http://localhost:9001/3.1/users/00000000000000000000000000000002')
Exemple #6
0
 def test_member_ids_are_hex(self):
     with transaction():
         subscribe(self._mlist, 'Anne')
         subscribe(self._mlist, 'Bart')
     response, headers = call_api('http://localhost:9001/3.1/members')
     entries = response['entries']
     self.assertEqual(len(entries), 2)
     self.assertEqual(
       entries[0]['self_link'],
       'http://localhost:9001/3.1/members/00000000000000000000000000000001')
     self.assertEqual(
         entries[0]['member_id'],
         '00000000000000000000000000000001')
     self.assertEqual(
         entries[0]['user'],
         'http://localhost:9001/3.1/users/00000000000000000000000000000001')
     self.assertEqual(
       entries[1]['self_link'],
       'http://localhost:9001/3.1/members/00000000000000000000000000000002')
     self.assertEqual(
         entries[1]['member_id'],
         '00000000000000000000000000000002')
     self.assertEqual(
         entries[1]['user'],
         'http://localhost:9001/3.1/users/00000000000000000000000000000002')
Exemple #7
0
 def test_delete_other_role(self):
     with transaction():
         subscribe(self._mlist, 'Anne', MemberRole.moderator)
     json, response = call_api('http://localhost:9001/3.0/members/1',
                               method='DELETE')
     self.assertEqual(response.status_code, 204)
     self.assertEqual(len(list(self._mlist.moderators.members)), 0)
 def test_no_welcome_message_to_moderators(self):
     # Welcome messages go only to mailing list members, not to moderators.
     subscribe(self._mlist, 'Anne', MemberRole.moderator,
               '*****@*****.**')
     # There is no welcome message in the virgin queue.
     messages = get_queue_messages('virgin')
     self.assertEqual(len(messages), 0)
Exemple #9
0
 def test_delete_other_role(self):
     with transaction():
         subscribe(self._mlist, 'Anne', MemberRole.moderator)
     response, headers = call_api(
         'http://localhost:9001/3.0/members/1',
         method='DELETE')
     self.assertEqual(headers.status, 204)
     self.assertEqual(len(list(self._mlist.moderators.members)), 0)
Exemple #10
0
 def test_simple_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     make_digest_messages(self._mlist)
     self._check_virgin_queue()
Exemple #11
0
 def test_simple_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     make_digest_messages(self._mlist)
     self._check_virgin_queue()
Exemple #12
0
    def test_mime_digest_format(self):
        # Make sure that the format of the MIME digest is as expected.
        self._mlist.digest_size_threshold = 0.6
        self._mlist.volume = 1
        self._mlist.next_digest_number = 1
        self._mlist.send_welcome_message = False
        # Subscribe some users receiving digests.
        anne = subscribe(self._mlist, 'Anne')
        anne.preferences.delivery_mode = DeliveryMode.mime_digests
        bart = subscribe(self._mlist, 'Bart')
        bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
        # Fill the digest.
        process = config.handlers['to-digest'].process
        size = 0
        for i in range(1, 5):
            text = Template("""\
From: [email protected]
To: [email protected]
Subject: Test message $i
List-Post: <*****@*****.**>

Here is message $i
""").substitute(i=i)
            msg = message_from_string(text)
            process(self._mlist, msg, {})
            size += len(text)
            if size >= self._mlist.digest_size_threshold * 1024:
                break
        # Run the digest runner to create the MIME and RFC 1153 digests.
        runner = make_testable_runner(DigestRunner)
        runner.run()
        items = get_queue_messages('virgin', expected_count=2)
        # Find the MIME one.
        mime_digest = None
        for item in items:
            if item.msg.is_multipart():
                assert mime_digest is None, 'We got two MIME digests'
                mime_digest = item.msg
        fp = StringIO()
        # Verify the structure is what we expect.
        structure(mime_digest, fp)
        self.assertMultiLineEqual(
            fp.getvalue(), """\
multipart/mixed
    text/plain
    text/plain
    multipart/digest
        message/rfc822
            text/plain
        message/rfc822
            text/plain
        message/rfc822
            text/plain
        message/rfc822
            text/plain
    text/plain
""")
Exemple #13
0
    def test_mime_digest_format(self):
        # Make sure that the format of the MIME digest is as expected.
        self._mlist.digest_size_threshold = 0.6
        self._mlist.volume = 1
        self._mlist.next_digest_number = 1
        self._mlist.send_welcome_message = False
        # Subscribe some users receiving digests.
        anne = subscribe(self._mlist, 'Anne')
        anne.preferences.delivery_mode = DeliveryMode.mime_digests
        bart = subscribe(self._mlist, 'Bart')
        bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
        # Fill the digest.
        process = config.handlers['to-digest'].process
        size = 0
        for i in range(1, 5):
            text = Template("""\
From: [email protected]
To: [email protected]
Subject: Test message $i
List-Post: <*****@*****.**>

Here is message $i
""").substitute(i=i)
            msg = message_from_string(text)
            process(self._mlist, msg, {})
            size += len(text)
            if size >= self._mlist.digest_size_threshold * 1024:
                break
        # Run the digest runner to create the MIME and RFC 1153 digests.
        runner = make_testable_runner(DigestRunner)
        runner.run()
        items = get_queue_messages('virgin')
        self.assertEqual(len(items), 2)
        # Find the MIME one.
        mime_digest = None
        for item in items:
            if item.msg.is_multipart():
                assert mime_digest is None, 'We got two MIME digests'
                mime_digest = item.msg
        fp = StringIO()
        # Verify the structure is what we expect.
        structure(mime_digest, fp)
        self.assertMultiLineEqual(fp.getvalue(), """\
multipart/mixed
    text/plain
    text/plain
    message/rfc822
        text/plain
    message/rfc822
        text/plain
    message/rfc822
        text/plain
    message/rfc822
        text/plain
    text/plain
""")
Exemple #14
0
 def test_patch_membership_with_bogus_address(self):
     # Try to change a subscription address to one that does not yet exist.
     with transaction():
         subscribe(self._mlist, 'Anne')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason, 'Address not registered')
 def test_sync_no_change(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         result = self._command.invoke(syncmembers, (
             '--no-change', infp.name, 'ant.example.com'))
     self.assertEqual(result.output, '[DEL] Bart Person'
                                     ' <*****@*****.**>\n')
     self.assertEqual(len(list(self._mlist.members.members)), 2)
Exemple #16
0
 def test_no_role(self):
     # Test for no matching roles.
     subscribe(self._mlist, 'Anne')
     result = self._command.invoke(findmember, (
         '--role',
         'owner',
         '.',
     ))
     self.assertEqual(result.exit_code, 0)
     self.assertEqual(result.output, '')
Exemple #17
0
 def test_patch_membership_with_bogus_address(self):
     # Try to change a subscription address to one that does not yet exist.
     with transaction():
         subscribe(self._mlist, 'Anne')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason, b'Address not registered')
Exemple #18
0
 def test_find_member_error(self):
     # .find_member() can only return zero or one memberships.  Anything
     # else is an error.
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Anne', MemberRole.owner)
     with self.assertRaises(TooManyMembersError) as cm:
         self._service.find_member('*****@*****.**')
     self.assertEqual(cm.exception.subscriber, '*****@*****.**')
     self.assertEqual(cm.exception.list_id, None)
     self.assertEqual(cm.exception.role, None)
Exemple #19
0
 def test_find_member_error(self):
     # .find_member() can only return zero or one memberships.  Anything
     # else is an error.
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Anne', MemberRole.owner)
     with self.assertRaises(TooManyMembersError) as cm:
         self._service.find_member('*****@*****.**')
     self.assertEqual(cm.exception.subscriber, '*****@*****.**')
     self.assertEqual(cm.exception.list_id, None)
     self.assertEqual(cm.exception.role, None)
Exemple #20
0
 def test_already_subscribed_with_display_name(self):
     subscribe(self._mlist, 'Anne')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         result = self._command.invoke(
             members, ('--add', infp.name, 'ant.example.com'))
     self.assertEqual(
         result.output,
         'Already subscribed (skipping): Anne Person <*****@*****.**>\n'
     )
Exemple #21
0
    def test_case_insensitive_pattern(self):
        # Test that patterns are case insensitive.
        subscribe(self._mlist, 'Anne')
        result = self._command.invoke(findmember, ('APerson', ))
        self.assertEqual(result.exit_code, 0)
        self.assertEqual(
            result.output, """\
Email: [email protected]
    List: ant.example.com
        MemberRole.member
""")
Exemple #22
0
 def test_patch_membership_with_unverified_address(self):
     # Try to change a subscription address to one that is not yet verified.
     with transaction():
         subscribe(self._mlist, 'Anne')
         self._usermanager.create_address('*****@*****.**')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason, b'Unverified address')
Exemple #23
0
    def test_basic_find(self):
        # Test a simple find of one membership.
        subscribe(self._mlist, 'Anne')
        result = self._command.invoke(findmember, ('.', ))
        self.assertEqual(result.exit_code, 0)
        self.assertEqual(
            result.output, """\
Email: [email protected]
    List: ant.example.com
        MemberRole.member
""")
Exemple #24
0
 def test_patch_membership_with_unverified_address(self):
     # Try to change a subscription address to one that is not yet verified.
     with transaction():
         subscribe(self._mlist, 'Anne')
         self._usermanager.create_address('*****@*****.**')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason, 'Unverified address')
Exemple #25
0
 def test_simple_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     make_digest_messages(self._mlist)
     self._check_virgin_queue()
     # The digest mbox and all intermediary mboxes must have been removed
     # (GL #259).
     self.assertEqual(os.listdir(self._mlist.data_path), [])
Exemple #26
0
 def test_sync_no_change(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         result = self._command.invoke(members, (
             '--no-change', '--sync', infp.name, 'ant.example.com'))
     self.assertEqual(
         result.output,
         'Warning: The --sync option is deprecated. '
         'Use `mailman syncmembers` instead.\n'
         '[DEL] Bart Person <*****@*****.**>\n')
Exemple #27
0
    def test_only_role(self):
        # Test only finding requested role.
        subscribe(self._mlist, 'Anne')
        subscribe(self._mlistb, 'Bart', role=MemberRole.owner)
        result = self._command.invoke(findmember, ('--role', 'owner', '.'))
        self.assertEqual(result.exit_code, 0)
        self.assertEqual(
            result.output, """\
Email: [email protected]
    List: bee.example.com
        MemberRole.owner
""")
 def test_override_yes_admin_notify(self):
     subscribe(self._mlist, 'Anne')
     self._mlist.admin_notify_mchanges = True
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('', file=infp)
         result = self._command.invoke(syncmembers, (
             '-A', infp.name, 'ant.example.com'))
     self.assertEqual(result.output,
                      '[DEL] Anne Person <*****@*****.**>\n')
     self.assertEqual(result.exit_code, 0)
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 0)
     get_queue_messages('virgin', expected_count=0)
Exemple #29
0
 def test_already_subscribed_with_display_name(self):
     subscribe(self._mlist, 'Anne')
     outfp = StringIO()
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         self.args.list = ['ant.example.com']
         self.args.input_filename = infp.name
         with patch('builtins.print', partial(print, file=outfp)):
             self.command.process(self.args)
     self.assertEqual(
        outfp.getvalue(),
        'Already subscribed (skipping): Anne Person <*****@*****.**>\n'
        )
 def test_already_subscribed_with_display_name(self):
     subscribe(self._mlist, 'Anne')
     outfp = StringIO()
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         self.args.list = ['ant.example.com']
         self.args.input_filename = infp.name
         with patch('builtins.print', partial(print, file=outfp)):
             self.command.process(self.args)
     self.assertEqual(
         outfp.getvalue(),
         'Already subscribed (skipping): Anne Person <*****@*****.**>\n'
     )
 def test_sync_empty_tuple(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         print('""', file=infp)
         result = self._command.invoke(syncmembers, (
             '--no-change', infp.name, 'ant.example.com'))
     self.assertEqual(result.output, "Cannot parse as valid email "
                                     "address (skipping): \"\"\n"
                                     "[DEL] Bart Person "
                                     "<*****@*****.**>\n")
     self.assertEqual(len(list(self._mlist.members.members)), 2)
 def test_sync_del_upper_case_email(self):
     subscribe(self._mlist, 'Bart', email='*****@*****.**')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('<*****@*****.**>', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(
        result.output,
        '[ADD] [email protected]\n'
        '[DEL] Bart Person <*****@*****.**>\n')
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 1)
     self.assertEqual(members[0].address.email, '*****@*****.**')
 def test_sync_commented_lines(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         print('#Bart Person <*****@*****.**>', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(result.output, '[DEL] Bart Person'
                                     ' <*****@*****.**>\n')
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 1)
     self.assertEqual(members[0].address.email, '*****@*****.**')
Exemple #34
0
 def test_patch_membership_of_preferred_address(self):
     # Try to change a subscription to an address when the user is
     # subscribed via their preferred address.
     with transaction():
         subscribe(self._mlist, 'Anne')
         anne = self._usermanager.create_address('*****@*****.**')
         anne.verified_on = now()
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason,
                      'Address is not controlled by user')
 def test_sync_nothing_to_do(self):
     subscribe(self._mlist, 'Anne')
     subscribe(self._mlist, 'Bart')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('Anne Person <*****@*****.**>', file=infp)
         print('Bart Person <*****@*****.**>', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(result.output, "Nothing to do\n")
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 2)
     addresses = [member.address.original_email for member in members]
     self.assertIn('*****@*****.**', addresses)
     self.assertIn('*****@*****.**', addresses)
 def test_sync_no_display_name(self):
     subscribe(self._mlist, 'Bart')
     subscribe(self._mlist, 'Cate', role=MemberRole.nonmember)
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('<*****@*****.**>', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(
        result.output,
        '[ADD] [email protected]\n'
        '[DEL] Bart Person <*****@*****.**>\n')
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 1)
     self.assertEqual(members[0].address.email, '*****@*****.**')
Exemple #37
0
 def test_process_digest(self):
     # MIME digests messages are multiparts.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     make_digest_messages(self._mlist)
     items = get_queue_messages('virgin', expected_count=2)
     for item in items:
         try:
             cook_headers.process(self._mlist, item.msg, {})
         except AttributeError as error:
             # LP: #1130696 would raise an AttributeError on .sender
             self.fail(error)
Exemple #38
0
 def test_patch_membership_of_preferred_address(self):
     # Try to change a subscription to an address when the user is
     # subscribed via their preferred address.
     with transaction():
         subscribe(self._mlist, 'Anne')
         anne = self._usermanager.create_address('*****@*****.**')
         anne.verified_on = now()
     with self.assertRaises(HTTPError) as cm:
         call_api('http://*****:*****@example.com',
             }, method='PATCH')
     self.assertEqual(cm.exception.code, 400)
     self.assertEqual(cm.exception.reason,
                      b'Address is not controlled by user')
 def test_no_override_goodbye(self):
     self._mlist.send_goodbye_message = True
     subscribe(self._mlist, 'Anne')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(result.output,
                      '[DEL] Anne Person <*****@*****.**>\n')
     self.assertEqual(result.exit_code, 0)
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 0)
     items = get_queue_messages('virgin', expected_count=1)
     self.assertIn('You have been unsubscribed',
                   str(items[0].msg['subject']))
 def test_sync_no_del_upper_case_email(self):
     subscribe(self._mlist, 'Bart', email='*****@*****.**')
     with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp:
         print('<*****@*****.**>', file=infp)
         print('*****@*****.**', file=infp)
         result = self._command.invoke(syncmembers, (
             infp.name, 'ant.example.com'))
     self.assertEqual(
        result.output,
        '[ADD] [email protected]\n')
     members = list(self._mlist.members.members)
     self.assertEqual(len(members), 2)
     addresses = [member.address.original_email for member in members]
     self.assertIn('*****@*****.**', addresses)
     self.assertIn('*****@*****.**', addresses)
    def test_welcome_message(self):
        subscribe(self._mlist, 'Anne', email='*****@*****.**')
        # Now there's one message in the virgin queue.
        items = get_queue_messages('virgin', expected_count=1)
        message = items[0].msg
        self.assertEqual(str(message['subject']),
                         'Welcome to the "Test List" mailing list')
        self.assertMultiLineEqual(message.get_payload(), """\
Welcome to the Test List mailing list.

    Posting address: [email protected]
    Help and other requests: [email protected]
    Your name: Anne Person
    Your address: [email protected]
""")
 def test_process_digest(self):
     # MIME digests messages are multiparts.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     make_digest_messages(self._mlist)
     messages = [bag.msg for bag in get_queue_messages('virgin')]
     self.assertEqual(len(messages), 2)
     for msg in messages:
         try:
             cook_headers.process(self._mlist, msg, {})
         except AttributeError as error:
             # LP: #1130696 would raise an AttributeError on .sender
             self.fail(error)
Exemple #43
0
    def setUp(self):
        self._mlist = create_list('*****@*****.**')
        self._mlist.personalize = Personalization.individual
        # Make Anne a member of this mailing list.
        self._anne = subscribe(self._mlist, 'Anne', email='*****@*****.**')
        # Clear out any results from the previous test.
        del _deliveries[:]
        self._msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: test

""")
        # Set up a personalized footer for decoration.
        self._template_dir = tempfile.mkdtemp()
        path = os.path.join(self._template_dir,
                            'site', 'en', 'member-footer.txt')
        os.makedirs(os.path.dirname(path))
        with open(path, 'w') as fp:
            print("""\
address  : $user_address
delivered: $user_delivered_to
language : $user_language
name     : $user_name
options  : $user_optionsurl
""", file=fp)
        config.push('templates', """
        [paths.testing]
        template_dir: {0}
        """.format(self._template_dir))
        self._mlist.footer_uri = 'mailman:///member-footer.txt'
        # Let assertMultiLineEqual work without bounds.
        self.maxDiff = None
Exemple #44
0
    def setUp(self):
        self._mlist = create_list('*****@*****.**')
        self._member = subscribe(self._mlist, 'Anne', email='*****@*****.**')
        self._msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: You bounced
Message-ID: <first>

""")
        # Set up the translation context.
        self._var_dir = tempfile.mkdtemp()
        xx_template_path = os.path.join(
            self._var_dir, 'templates', 'site', 'xx', 'probe.txt')
        os.makedirs(os.path.dirname(xx_template_path))
        config.push('xx template dir', """\
        [paths.testing]
        var_dir: {0}
        """.format(self._var_dir))
        language_manager = getUtility(ILanguageManager)
        language_manager.add('xx', 'utf-8', 'Freedonia')
        self._member.preferences.preferred_language = 'xx'
        with open(xx_template_path, 'w') as fp:
            print("""\
blah blah blah
$listname
$address
$optionsurl
$owneraddr
""", file=fp)
        # Let assertMultiLineEqual work without bounds.
        self.maxDiff = None
Exemple #45
0
    def test_issue141_one_last_digest(self):
        # Currently DigestMode.summary_digests are equivalent to mime_digests.
        self._mlist.send_welcome_message = False
        bart = subscribe(self._mlist, 'Bart')
        self._mlist.send_one_last_digest_to(
            bart.address, DeliveryMode.summary_digests)
        make_digest_messages(self._mlist)
        # There should be one message in the outgoing queue, destined for
        # Bart, formatted as a MIME digest.
        items = get_queue_messages('virgin')
        self.assertEqual(len(items), 1)
        # Bart is the only recipient.
        self.assertEqual(items[0].msgdata['recipients'],
                         set(['*****@*****.**']))
        # The message is a MIME digest, with the structure we expect.
        fp = StringIO()
        structure(items[0].msg, fp)
        self.assertMultiLineEqual(fp.getvalue(), """\
multipart/mixed
    text/plain
    text/plain
    message/rfc822
        text/plain
    text/plain
""")
    def test_welcome_message(self):
        subscribe(self._mlist, 'Anne', email='*****@*****.**')
        # Now there's one message in the virgin queue.
        messages = get_queue_messages('virgin')
        self.assertEqual(len(messages), 1)
        message = messages[0].msg
        self.assertEqual(str(message['subject']),
                         'Welcome to the "Test List" mailing list')
        self.assertMultiLineEqual(message.get_payload(), """\
Welcome to the Test List mailing list.

    Posting address: [email protected]
    Help and other requests: [email protected]
    Your name: Anne Person
    Your address: [email protected]
    Your options: http://example.com/[email protected]
""")
Exemple #47
0
 def test_get_list_member_id_by_email(self):
     with transaction():
         subscribe(self._mlist, 'Anne', email="*****@*****.**")
     response, headers = call_api(
         'http://*****:*****@example.com')
     self.assertEqual(response['member_id'],
                      '00000000000000000000000000000001')
     self.assertEqual(
       response['self_link'],
       'http://*****:*****@example.com')
Exemple #48
0
 def test_all_preferences(self):
     with transaction():
         member = subscribe(self._mlist, 'Anne')
         member.preferences.delivery_mode = DeliveryMode.summary_digests
     response, headers = call_api(
         'http://localhost:9001/3.1/members'
         '/00000000000000000000000000000001/all/preferences')
     self.assertEqual(response['delivery_mode'], 'summary_digests')
Exemple #49
0
 def setUp(self):
     self._mlist = create_list('*****@*****.**')
     self._mlist.send_welcome_message = False
     self._mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
     # The mailing list needs at least one digest recipient.
     member = subscribe(self._mlist, 'Anne')
     member.preferences.delivery_mode = DeliveryMode.plaintext_digests
     self._subject_number = 1
     self._runner = make_testable_runner(DigestRunner, 'digest')
    def test_welcome_message(self):
        subscribe(self._mlist, "Anne", email="*****@*****.**")
        # Now there's one message in the virgin queue.
        items = get_queue_messages("virgin", expected_count=1)
        message = items[0].msg
        self.assertEqual(str(message["subject"]), 'Welcome to the "Test List" mailing list')
        self.assertMultiLineEqual(
            message.get_payload(),
            """\
Welcome to the Test List mailing list.

    Posting address: [email protected]
    Help and other requests: [email protected]
    Your name: Anne Person
    Your address: [email protected]
    Your options: http://example.com/[email protected]
""",
        )
Exemple #51
0
 def setUp(self):
     self._mlist = create_list('*****@*****.**')
     self._mlist.digests_enabled = True
     self._mlist.digest_size_threshold = 100000
     self._mlist.send_welcome_message = False
     self._command = Digests()
     self._handler = config.handlers['to-digest']
     self._runner = make_testable_runner(DigestRunner, 'digest')
     # The mailing list needs at least one digest recipient.
     member = subscribe(self._mlist, 'Anne')
     member.preferences.delivery_mode = DeliveryMode.plaintext_digests
Exemple #52
0
    def setUp(self):
        self._mlist = create_list('*****@*****.**')
        self._mlist.send_welcome_message = False
        self._member = subscribe(self._mlist, 'Anne', email='*****@*****.**')
        self._msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: You bounced
Message-ID: <first>

""")
Exemple #53
0
 def test_non_ascii_message(self):
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     msg = Message()
     msg['From'] = '*****@*****.**'
     msg['To'] = '*****@*****.**'
     msg['Content-Type'] = 'multipart/mixed'
     msg.attach(MIMEText('message with non-ascii chars: \xc3\xa9',
                         'plain', 'utf-8'))
     mbox = digest_mbox(self._mlist)
     mbox.add(msg.as_string())
     # Use any error logs as the error message if the test fails.
     error_log = LogFileMark('mailman.error')
     make_digest_messages(self._mlist, msg)
     # The runner will send the file to the shunt queue on exception.
     self.assertEqual(len(self._shuntq.files), 0, error_log.read())
     self._check_virgin_queue()
Exemple #54
0
 def test_role_moderator(self):
     subscribe(self._mlist, 'Anne', role=MemberRole.owner)
     subscribe(self._mlist, 'Bart', role=MemberRole.moderator)
     subscribe(self._mlist, 'Cate', role=MemberRole.nonmember)
     subscribe(self._mlist, 'Dave', role=MemberRole.member)
     self.args.list = ['ant.example.com']
     self.args.role = 'moderator'
     with NamedTemporaryFile('w', encoding='utf-8') as outfp:
         self.args.output_filename = outfp.name
         self.command.process(self.args)
         with open(outfp.name, 'r', encoding='utf-8') as infp:
             lines = infp.readlines()
     self.assertEqual(len(lines), 1)
     self.assertEqual(lines[0], 'Bart Person <*****@*****.**>\n')
Exemple #55
0
 def test_digest_messages(self):
     # In LP: #1130697, the digest runner creates MIME digests using the
     # stdlib MIMEMutlipart class, however this class does not have the
     # extended attributes we require (e.g. .sender).  The fix is to use a
     # subclass of MIMEMultipart and our own Message subclass; this adds
     # back the required attributes.  (LP: #1130696)
     self._mlist.send_welcome_message = False
     # Subscribe some users receiving digests.
     anne = subscribe(self._mlist, 'Anne')
     anne.preferences.delivery_mode = DeliveryMode.mime_digests
     bart = subscribe(self._mlist, 'Bart')
     bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
     # Start by creating the raw ingredients for the digests.  This also
     # runs the digest runner, thus producing the digest messages into the
     # virgin queue.
     make_digest_messages(self._mlist)
     # Run the virgin queue processor, which runs the cook-headers and
     # to-outgoing handlers.  This should produce no error.
     error_log = LogFileMark('mailman.error')
     runner = make_testable_runner(VirginRunner, 'virgin')
     runner.run()
     error_text = error_log.read()
     self.assertEqual(len(error_text), 0, error_text)
     self.assertEqual(len(get_queue_messages('shunt')), 0)
     messages = get_queue_messages('out')
     self.assertEqual(len(messages), 2)
     # Which one is the MIME digest?
     mime_digest = None
     for bag in messages:
         if bag.msg.get_content_type() == 'multipart/mixed':
             assert mime_digest is None, 'Found two MIME digests'
             mime_digest = bag.msg
     # The cook-headers handler ran.
     self.assertIn('x-mailman-version', mime_digest)
     self.assertEqual(mime_digest['precedence'], 'list')
     # The list's -request address is the original sender.
     self.assertEqual(bag.msgdata['original_sender'],
                      '*****@*****.**')
 def test_no_welcome_message_to_moderators(self):
     # Welcome messages go only to mailing list members, not to moderators.
     subscribe(self._mlist, "Anne", MemberRole.moderator, "*****@*****.**")
     # There is no welcome message in the virgin queue.
     get_queue_messages("virgin", expected_count=0)
Exemple #57
0
    def test_multilingual_digest(self):
        # When messages come in with a content-type character set different
        # than that of the list's preferred language, recipients will get an
        # internationalized digest.
        #
        # Subscribe some users receiving digests.
        anne = subscribe(self._mlist, 'Anne')
        anne.preferences.delivery_mode = DeliveryMode.mime_digests
        bart = subscribe(self._mlist, 'Bart')
        bart.preferences.delivery_mode = DeliveryMode.plaintext_digests
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: =?iso-2022-jp?b?GyRCMGxIVhsoQg==?=
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit

\x1b$B0lHV\x1b(B
""")
        self._process(self._mlist, msg, {})
        self._runner.run()
        # There are two digests in the virgin queue; one is the MIME digest
        # and the other is the RFC 1153 digest.
        messages = get_queue_messages('virgin')
        self.assertEqual(len(messages), 2)
        if messages[0].msg.is_multipart():
            mime, rfc1153 = messages[0].msg, messages[1].msg
        else:
            rfc1153, mime = messages[0].msg, messages[1].msg
        # The MIME version contains a mix of French and Japanese.  The digest
        # chrome added by Mailman is in French.
        self.assertEqual(mime['subject'].encode(),
                         '=?iso-8859-1?q?Groupe_Test=2C_Vol_1=2C_Parution_1?=')
        self.assertEqual(str(mime['subject']),
                         'Groupe Test, Vol 1, Parution 1')
        # The first subpart contains the iso-8859-1 masthead.
        masthead = mime.get_payload(0).get_payload(decode=True).decode(
            'iso-8859-1')
        self.assertMultiLineEqual(masthead.splitlines()[0],
                                  'Envoyez vos messages pour la liste Test à')
        # The second subpart contains the utf-8 table of contents.
        self.assertEqual(mime.get_payload(1)['content-description'],
                         "Today's Topics (1 messages)")
        toc = mime.get_payload(1).get_payload(decode=True).decode('utf-8')
        self.assertMultiLineEqual(toc.splitlines()[0], 'Thèmes du jour :')
        # The third subpart contains the posted message in Japanese.
        self.assertEqual(mime.get_payload(2).get_content_type(),
                         'message/rfc822')
        post = mime.get_payload(2).get_payload(0)
        self.assertEqual(post['subject'], '=?iso-2022-jp?b?GyRCMGxIVhsoQg==?=')
        # Compare the bytes so that this module doesn't contain string
        # literals in multiple incompatible character sets.
        self.assertEqual(post.get_payload(decode=True), b'\x1b$B0lHV\x1b(B\n')
        # The RFC 1153 digest will have the same subject, but its payload will
        # be recast into utf-8.
        self.assertEqual(str(rfc1153['subject']),
                         'Groupe Test, Vol 1, Parution 1')
        self.assertEqual(rfc1153.get_charset(), 'utf-8')
        lines = rfc1153.get_payload(decode=True).decode('utf-8').splitlines()
        self.assertEqual(lines[0], 'Envoyez vos messages pour la liste Test à')
Exemple #58
0
    def test_send_digests_for_all_lists(self):
        # Populate ant's digest.
        msg = mfs("""\
To: [email protected]
From: [email protected]
Subject: message 1

""")
        self._handler.process(self._mlist, msg, {})
        del msg['subject']
        msg['subject'] = 'message 2'
        self._handler.process(self._mlist, msg, {})
        # Create the second list.
        bee = create_list('*****@*****.**')
        bee.digests_enabled = True
        bee.digest_size_threshold = 100000
        bee.send_welcome_message = False
        member = subscribe(bee, 'Bart')
        member.preferences.delivery_mode = DeliveryMode.plaintext_digests
        # Populate bee's digest.
        msg = mfs("""\
To: [email protected]
From: [email protected]
Subject: message 3

""")
        self._handler.process(bee, msg, {})
        del msg['subject']
        msg['subject'] = 'message 4'
        self._handler.process(bee, msg, {})
        # There are no digests for either list already being sent, but the
        # mailing lists do have a digest mbox collecting messages.
        ant_mailbox_path = os.path.join(self._mlist.data_path, 'digest.mmdf')
        self.assertGreater(os.path.getsize(ant_mailbox_path), 0)
        # Check bee's digest.
        bee_mailbox_path = os.path.join(bee.data_path, 'digest.mmdf')
        self.assertGreater(os.path.getsize(bee_mailbox_path), 0)
        # Both.
        get_queue_messages('digest', expected_count=0)
        # Process all mailing list digests by not setting any arguments.
        args = FakeArgs()
        args.send = True
        self._command.process(args)
        self._runner.run()
        # Now, neither list has a digest mbox and but there are plaintext
        # digest in the outgoing queue for both.
        self.assertFalse(os.path.exists(ant_mailbox_path))
        self.assertFalse(os.path.exists(bee_mailbox_path))
        items = get_queue_messages('virgin', expected_count=2)
        # Figure out which digest is going to ant and which to bee.
        if items[0].msg['to'] == '*****@*****.**':
            ant = items[0].msg
            bee = items[1].msg
        else:
            assert items[0].msg['to'] == '*****@*****.**'
            ant = items[1].msg
            bee = items[0].msg
        # Check ant's digest.
        digest_contents = str(ant)
        self.assertIn('Subject: message 1', digest_contents)
        self.assertIn('Subject: message 2', digest_contents)
        # Check bee's digest.
        digest_contents = str(bee)
        self.assertIn('Subject: message 3', digest_contents)
        self.assertIn('Subject: message 4', digest_contents)
Exemple #59
0
 def test_cannot_get_member_id_by_int(self):
     with transaction():
         subscribe(self._mlist, 'Anne')
     with self.assertRaises(HTTPError) as cm:
         call_api('http://localhost:9001/3.1/members/1')
     self.assertEqual(cm.exception.code, 404)