# Copyright (C) 2012-2017 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # # GNU Mailman is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # GNU Mailman. If not, see . """Test mailing list joins.""" import unittest from email.iterators import body_line_iterator from mailman.app.lifecycle import create_list from mailman.config import config from mailman.interfaces.member import DeliveryMode from mailman.interfaces.subscriptions import ( ISubscriptionManager, ISubscriptionService, TokenOwner) from mailman.interfaces.usermanager import IUserManager from mailman.runners.command import CommandRunner from mailman.testing.helpers import ( get_queue_messages, make_testable_runner, specialized_message_from_string as mfs) from mailman.testing.layers import ConfigLayer from zope.component import getUtility class TestJoin(unittest.TestCase): """Test mailing list joins.""" layer = ConfigLayer def setUp(self): self._mlist = create_list('test@example.com') self._mlist.send_welcome_message = False self._commandq = config.switchboards['command'] self._runner = make_testable_runner(CommandRunner, 'command') def test_double_confirmation(self): # A join request comes in using both the -join address and the word # 'subscribe' in the first line of the body. This should produce just # one subscription request and one confirmation response. msg = mfs("""\ From: anne@example.org To: test-join@example.com subscribe """) # Adding the subaddress to the metadata dictionary mimics what happens # when the above email message is first processed by the lmtp runner. # For convenience, we skip that step in this test. self._commandq.enqueue(msg, dict(listid='test.example.com', subaddress='join')) self._runner.run() # There will be two messages in the queue. The first one is a reply # to Anne notifying her of the status of her command email. The # second one is the confirmation message of her join request. items = get_queue_messages('virgin', sort_on='subject', expected_count=2) self.assertTrue(str(items[1].msg['subject']).startswith('confirm')) self.assertEqual(items[0].msg['subject'], 'The results of your email commands') # Search the contents of the results message. There should be just # one 'Confirmation email' line. confirmation_lines = [] in_results = False for line in body_line_iterator(items[0].msg): line = line.strip() if in_results: if line.startswith('- Done'): break if len(line) > 0: confirmation_lines.append(line) if line.strip() == '- Results:': in_results = True # There should be exactly one confirmation line. self.assertEqual(len(confirmation_lines), 1) # And the confirmation line should name Anne's email address. self.assertIn('anne@example.org', confirmation_lines[0]) def test_join_when_already_a_member(self): anne = getUtility(IUserManager).create_user('anne@example.org') self._mlist.subscribe(list(anne.addresses)[0]) # When someone tries to join by email and they are already a member, # ignore the request. msg = mfs("""\ From: anne@example.org To: test-join@example.com Subject: join """) self._commandq.enqueue(msg, dict(listid='test.example.com')) self._runner.run() # There will be one message in the queue - a reply to Anne notifying # her of the status of her command email. Because Anne is already # subscribed to the list, she gets and needs no confirmation. items = get_queue_messages('virgin', expected_count=1) self.assertEqual(items[0].msg['subject'], 'The results of your email commands') # Search the contents of the results message. There should be just # one 'Confirmation email' line. confirmation_lines = [] in_results = False for line in body_line_iterator(items[0].msg): line = line.strip() if in_results: if line.startswith('- Done'): break if len(line) > 0: confirmation_lines.append(line) if line.strip() == '- Results:': in_results = True # There should be exactly one confirmation line. self.assertEqual(len(confirmation_lines), 1) # And the confirmation line should name Anne's email address. self.assertIn('anne@example.org', confirmation_lines[0]) class TestJoinWithDigests(unittest.TestCase): """Test mailing list joins with the digests= argument.""" layer = ConfigLayer def setUp(self): self._mlist = create_list('test@example.com') self._commandq = config.switchboards['command'] self._runner = make_testable_runner(CommandRunner, 'command') def _confirm(self): # There will be two messages in the queue - the confirmation messages, # and a reply to Anne notifying her of the status of her command # email. We need to dig the confirmation token out of the Subject # header of the latter so that we can confirm the subscription. items = get_queue_messages('virgin', sort_on='subject', expected_count=2) subject_words = str(items[1].msg['subject']).split() self.assertEqual(subject_words[0], 'confirm') token = subject_words[1] token, token_owner, rmember = ISubscriptionManager( self._mlist).confirm(token) self.assertIsNone(token) self.assertEqual(token_owner, TokenOwner.no_one) # Now, make sure that Anne is a member of the list and is receiving # digest deliveries. members = getUtility(ISubscriptionService).find_members( 'anne@example.org') self.assertEqual(len(members), 1) self.assertEqual(rmember, members[0]) return rmember def test_join_with_implicit_no_digests(self): # Test the digest=mime argument to the join command. msg = mfs("""\ From: anne@example.org To: test-request@example.com join """) self._commandq.enqueue(msg, dict(listid='test.example.com')) self._runner.run() anne = self._confirm() self.assertEqual(anne.address.email, 'anne@example.org') self.assertEqual(anne.delivery_mode, DeliveryMode.regular) def test_join_with_explicit_no_digests(self): # Test the digest=mime argument to the join command. msg = mfs("""\ From: anne@example.org To: test-request@example.com join digest=no """) self._commandq.enqueue(msg, dict(listid='test.example.com')) self._runner.run() anne = self._confirm() self.assertEqual(anne.address.email, 'anne@example.org') self.assertEqual(anne.delivery_mode, DeliveryMode.regular) # LP: #1444184 - digest=mime is not currently supported. @unittest.expectedFailure def test_join_with_mime_digests(self): # Test the digest=mime argument to the join command. msg = mfs("""\ From: anne@example.org To: test-request@example.com join digest=mime """) self._commandq.enqueue(msg, dict(listid='test.example.com')) self._runner.run() anne = self._confirm() self.assertEqual(anne.address.email, 'anne@example.org') self.assertEqual(anne.delivery_mode, DeliveryMode.mime_digests) # LP: #1444184 - digest=mime is not currently supported. @unittest.expectedFailure def test_join_with_plain_digests(self): # Test the digest=mime argument to the join command. msg = mfs("""\ From: anne@example.org To: test-request@example.com join digest=plain """) self._commandq.enqueue(msg, dict(listid='test.example.com')) self._runner.run() anne = self._confirm() self.assertEqual(anne.address.email, 'anne@example.org') self.assertEqual(anne.delivery_mode, DeliveryMode.plaintext_digests)