summaryrefslogtreecommitdiff
path: root/src/mailman/app/tests/test_subscriptions.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/app/tests/test_subscriptions.py')
-rw-r--r--src/mailman/app/tests/test_subscriptions.py720
1 files changed, 0 insertions, 720 deletions
diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py
deleted file mode 100644
index 0519ec385..000000000
--- a/src/mailman/app/tests/test_subscriptions.py
+++ /dev/null
@@ -1,720 +0,0 @@
-# Copyright (C) 2011-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 <http://www.gnu.org/licenses/>.
-
-"""Tests for the subscription service."""
-
-import unittest
-
-from contextlib import suppress
-from mailman.app.lifecycle import create_list
-from mailman.app.subscriptions import SubscriptionWorkflow
-from mailman.interfaces.bans import IBanManager
-from mailman.interfaces.mailinglist import SubscriptionPolicy
-from mailman.interfaces.member import MemberRole, MembershipIsBannedError
-from mailman.interfaces.pending import IPendings
-from mailman.interfaces.subscriptions import TokenOwner
-from mailman.interfaces.usermanager import IUserManager
-from mailman.testing.helpers import (
- LogFileMark, get_queue_messages, set_preferred)
-from mailman.testing.layers import ConfigLayer
-from mailman.utilities.datetime import now
-from unittest.mock import patch
-from zope.component import getUtility
-
-
-class TestSubscriptionWorkflow(unittest.TestCase):
- layer = ConfigLayer
- maxDiff = None
-
- def setUp(self):
- self._mlist = create_list('test@example.com')
- self._mlist.admin_immed_notify = False
- self._anne = 'anne@example.com'
- self._user_manager = getUtility(IUserManager)
- self._expected_pendings_count = 0
-
- def tearDown(self):
- # There usually should be no pending after all is said and done, but
- # some tests don't complete the workflow.
- self.assertEqual(getUtility(IPendings).count,
- self._expected_pendings_count)
-
- def test_start_state(self):
- # The workflow starts with no tokens or member.
- workflow = SubscriptionWorkflow(self._mlist)
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
- self.assertIsNone(workflow.member)
-
- def test_pended_data(self):
- # There is a Pendable associated with the held request, and it has
- # some data associated with it.
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- with suppress(StopIteration):
- workflow.run_thru('send_confirmation')
- self.assertIsNotNone(workflow.token)
- pendable = getUtility(IPendings).confirm(workflow.token, expunge=False)
- self.assertEqual(pendable['list_id'], 'test.example.com')
- self.assertEqual(pendable['email'], 'anne@example.com')
- self.assertEqual(pendable['display_name'], '')
- self.assertEqual(pendable['when'], '2005-08-01T07:49:23')
- self.assertEqual(pendable['token_owner'], 'subscriber')
- # The token is still in the database.
- self._expected_pendings_count = 1
-
- def test_user_or_address_required(self):
- # The `subscriber` attribute must be a user or address.
- workflow = SubscriptionWorkflow(self._mlist)
- self.assertRaises(AssertionError, list, workflow)
-
- def test_sanity_checks_address(self):
- # Ensure that the sanity check phase, when given an IAddress, ends up
- # with a linked user.
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- self.assertIsNotNone(workflow.address)
- self.assertIsNone(workflow.user)
- workflow.run_thru('sanity_checks')
- self.assertIsNotNone(workflow.address)
- self.assertIsNotNone(workflow.user)
- self.assertEqual(list(workflow.user.addresses)[0].email, self._anne)
-
- def test_sanity_checks_user_with_preferred_address(self):
- # Ensure that the sanity check phase, when given an IUser with a
- # preferred address, ends up with an address.
- anne = self._user_manager.make_user(self._anne)
- address = set_preferred(anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- # The constructor sets workflow.address because the user has a
- # preferred address.
- self.assertEqual(workflow.address, address)
- self.assertEqual(workflow.user, anne)
- workflow.run_thru('sanity_checks')
- self.assertEqual(workflow.address, address)
- self.assertEqual(workflow.user, anne)
-
- def test_sanity_checks_user_without_preferred_address(self):
- # Ensure that the sanity check phase, when given a user without a
- # preferred address, but with at least one linked address, gets an
- # address.
- anne = self._user_manager.make_user(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- self.assertIsNone(workflow.address)
- self.assertEqual(workflow.user, anne)
- workflow.run_thru('sanity_checks')
- self.assertIsNotNone(workflow.address)
- self.assertEqual(workflow.user, anne)
-
- def test_sanity_checks_user_with_multiple_linked_addresses(self):
- # Ensure that the santiy check phase, when given a user without a
- # preferred address, but with multiple linked addresses, gets of of
- # those addresses (exactly which one is undefined).
- anne = self._user_manager.make_user(self._anne)
- anne.link(self._user_manager.create_address('anne@example.net'))
- anne.link(self._user_manager.create_address('anne@example.org'))
- workflow = SubscriptionWorkflow(self._mlist, anne)
- self.assertIsNone(workflow.address)
- self.assertEqual(workflow.user, anne)
- workflow.run_thru('sanity_checks')
- self.assertIn(workflow.address.email, ['anne@example.com',
- 'anne@example.net',
- 'anne@example.org'])
- self.assertEqual(workflow.user, anne)
-
- def test_sanity_checks_user_without_addresses(self):
- # It is an error to try to subscribe a user with no linked addresses.
- user = self._user_manager.create_user()
- workflow = SubscriptionWorkflow(self._mlist, user)
- self.assertRaises(AssertionError, workflow.run_thru, 'sanity_checks')
-
- def test_sanity_checks_globally_banned_address(self):
- # An exception is raised if the address is globally banned.
- anne = self._user_manager.create_address(self._anne)
- IBanManager(None).ban(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- self.assertRaises(MembershipIsBannedError, list, workflow)
-
- def test_sanity_checks_banned_address(self):
- # An exception is raised if the address is banned by the mailing list.
- anne = self._user_manager.create_address(self._anne)
- IBanManager(self._mlist).ban(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- self.assertRaises(MembershipIsBannedError, list, workflow)
-
- def test_verification_checks_with_verified_address(self):
- # When the address is already verified, we skip straight to the
- # confirmation checks.
- anne = self._user_manager.create_address(self._anne)
- anne.verified_on = now()
- workflow = SubscriptionWorkflow(self._mlist, anne)
- workflow.run_thru('verification_checks')
- with patch.object(workflow, '_step_confirmation_checks') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_verification_checks_with_pre_verified_address(self):
- # When the address is not yet verified, but the pre-verified flag is
- # passed to the workflow, we skip to the confirmation checks.
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('verification_checks')
- with patch.object(workflow, '_step_confirmation_checks') as step:
- next(workflow)
- step.assert_called_once_with()
- # And now the address is verified.
- self.assertIsNotNone(anne.verified_on)
-
- def test_verification_checks_confirmation_needed(self):
- # The address is neither verified, nor is the pre-verified flag set.
- # A confirmation message must be sent to the user which will also
- # verify their address.
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- workflow.run_thru('verification_checks')
- with patch.object(workflow, '_step_send_confirmation') as step:
- next(workflow)
- step.assert_called_once_with()
- # The address still hasn't been verified.
- self.assertIsNone(anne.verified_on)
-
- def test_confirmation_checks_open_list(self):
- # A subscription to an open list does not need to be confirmed or
- # moderated.
- self._mlist.subscription_policy = SubscriptionPolicy.open
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_do_subscription') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_no_user_confirmation_needed(self):
- # A subscription to a list which does not need user confirmation skips
- # to the moderation checks.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_moderation_checks') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_confirm_pre_confirmed(self):
- # The subscription policy requires user confirmation, but their
- # subscription is pre-confirmed. Since moderation is not required,
- # the user will be immediately subscribed.
- self._mlist.subscription_policy = SubscriptionPolicy.confirm
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_do_subscription') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_confirm_then_moderate_pre_confirmed(self):
- # The subscription policy requires user confirmation, but their
- # subscription is pre-confirmed. Since moderation is required, that
- # check will be performed.
- self._mlist.subscription_policy = (
- SubscriptionPolicy.confirm_then_moderate)
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_moderation_checks') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_confirm_and_moderate_pre_confirmed(self):
- # The subscription policy requires user confirmation and moderation,
- # but their subscription is pre-confirmed.
- self._mlist.subscription_policy = (
- SubscriptionPolicy.confirm_then_moderate)
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_moderation_checks') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_confirmation_needed(self):
- # The subscription policy requires confirmation and the subscription
- # is not pre-confirmed.
- self._mlist.subscription_policy = SubscriptionPolicy.confirm
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_send_confirmation') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_confirmation_checks_moderate_confirmation_needed(self):
- # The subscription policy requires confirmation and moderation, and the
- # subscription is not pre-confirmed.
- self._mlist.subscription_policy = (
- SubscriptionPolicy.confirm_then_moderate)
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('confirmation_checks')
- with patch.object(workflow, '_step_send_confirmation') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_moderation_checks_pre_approved(self):
- # The subscription is pre-approved by the moderator.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_approved=True)
- workflow.run_thru('moderation_checks')
- with patch.object(workflow, '_step_do_subscription') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_moderation_checks_approval_required(self):
- # The moderator must approve the subscription.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- workflow.run_thru('moderation_checks')
- with patch.object(workflow, '_step_get_moderator_approval') as step:
- next(workflow)
- step.assert_called_once_with()
-
- def test_do_subscription(self):
- # An open subscription policy plus a pre-verified address means the
- # user gets subscribed to the mailing list without any further
- # confirmations or approvals.
- self._mlist.subscription_policy = SubscriptionPolicy.open
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- # Consume the entire state machine.
- list(workflow)
- # Anne is now a member of the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(workflow.member, member)
- # No further token is needed.
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
-
- def test_do_subscription_pre_approved(self):
- # An moderation-requiring subscription policy plus a pre-verified and
- # pre-approved address means the user gets subscribed to the mailing
- # list without any further confirmations or approvals.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_approved=True)
- # Consume the entire state machine.
- list(workflow)
- # Anne is now a member of the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(workflow.member, member)
- # No further token is needed.
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
-
- def test_do_subscription_pre_approved_pre_confirmed(self):
- # An moderation-requiring subscription policy plus a pre-verified and
- # pre-approved address means the user gets subscribed to the mailing
- # list without any further confirmations or approvals.
- self._mlist.subscription_policy = (
- SubscriptionPolicy.confirm_then_moderate)
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True,
- pre_approved=True)
- # Consume the entire state machine.
- list(workflow)
- # Anne is now a member of the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(workflow.member, member)
- # No further token is needed.
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
-
- def test_do_subscription_cleanups(self):
- # Once the user is subscribed, the token, and its associated pending
- # database record will be removed from the database.
- self._mlist.subscription_policy = SubscriptionPolicy.open
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True,
- pre_approved=True)
- # Consume the entire state machine.
- list(workflow)
- # Anne is now a member of the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(workflow.member, member)
- # The workflow is done, so it has no token.
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
-
- def test_moderator_approves(self):
- # The workflow runs until moderator approval is required, at which
- # point the workflow is saved. Once the moderator approves, the
- # workflow resumes and the user is subscribed.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- # Consume the entire state machine.
- list(workflow)
- # The user is not currently subscribed to the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertIsNone(member)
- self.assertIsNone(workflow.member)
- # The token is owned by the moderator.
- self.assertIsNotNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.moderator)
- # Create a new workflow with the previous workflow's save token, and
- # restore its state. This models an approved subscription and should
- # result in the user getting subscribed.
- approved_workflow = SubscriptionWorkflow(self._mlist)
- approved_workflow.token = workflow.token
- approved_workflow.restore()
- list(approved_workflow)
- # Now the user is subscribed to the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(approved_workflow.member, member)
- # No further token is needed.
- self.assertIsNone(approved_workflow.token)
- self.assertEqual(approved_workflow.token_owner, TokenOwner.no_one)
-
- def test_get_moderator_approval_log_on_hold(self):
- # When the subscription is held for moderator approval, a message is
- # logged.
- mark = LogFileMark('mailman.subscribe')
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- # Consume the entire state machine.
- list(workflow)
- self.assertIn(
- 'test@example.com: held subscription request from anne@example.com',
- mark.readline()
- )
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_get_moderator_approval_notifies_moderators(self):
- # When the subscription is held for moderator approval, and the list
- # is so configured, a notification is sent to the list moderators.
- self._mlist.admin_immed_notify = True
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- bart = self._user_manager.create_user('bart@example.com', 'Bart User')
- address = set_preferred(bart)
- self._mlist.subscribe(address, MemberRole.moderator)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- # Consume the entire state machine.
- list(workflow)
- # Find the moderator message.
- items = get_queue_messages('virgin', expected_count=1)
- for item in items:
- if item.msg['to'] == 'test-owner@example.com':
- break
- else:
- raise AssertionError('No moderator email found')
- self.assertEqual(
- item.msgdata['recipients'], {'test-owner@example.com'})
- message = items[0].msg
- self.assertEqual(message['From'], 'test-owner@example.com')
- self.assertEqual(message['To'], 'test-owner@example.com')
- self.assertEqual(
- message['Subject'],
- 'New subscription request to Test from anne@example.com')
- self.assertEqual(message.get_payload(), """\
-Your authorization is required for a mailing list subscription request
-approval:
-
- For: anne@example.com
- List: test@example.com
-""")
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_get_moderator_approval_no_notifications(self):
- # When the subscription is held for moderator approval, and the list
- # is so configured, a notification is sent to the list moderators.
- self._mlist.admin_immed_notify = False
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne,
- pre_verified=True,
- pre_confirmed=True)
- # Consume the entire state machine.
- list(workflow)
- get_queue_messages('virgin', expected_count=0)
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_send_confirmation(self):
- # A confirmation message gets sent when the address is not verified.
- anne = self._user_manager.create_address(self._anne)
- self.assertIsNone(anne.verified_on)
- # Run the workflow to model the confirmation step.
- workflow = SubscriptionWorkflow(self._mlist, anne)
- list(workflow)
- items = get_queue_messages('virgin', expected_count=1)
- message = items[0].msg
- token = workflow.token
- self.assertEqual(message['Subject'], 'confirm {}'.format(token))
- self.assertEqual(
- message['From'], 'test-confirm+{}@example.com'.format(token))
- # The confirmation message is not `Precedence: bulk`.
- self.assertIsNone(message['precedence'])
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_send_confirmation_pre_confirmed(self):
- # A confirmation message gets sent when the address is not verified
- # but the subscription is pre-confirmed.
- anne = self._user_manager.create_address(self._anne)
- self.assertIsNone(anne.verified_on)
- # Run the workflow to model the confirmation step.
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_confirmed=True)
- list(workflow)
- items = get_queue_messages('virgin', expected_count=1)
- message = items[0].msg
- token = workflow.token
- self.assertEqual(
- message['Subject'], 'confirm {}'.format(workflow.token))
- self.assertEqual(
- message['From'], 'test-confirm+{}@example.com'.format(token))
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_send_confirmation_pre_verified(self):
- # A confirmation message gets sent even when the address is verified
- # when the subscription must be confirmed.
- self._mlist.subscription_policy = SubscriptionPolicy.confirm
- anne = self._user_manager.create_address(self._anne)
- self.assertIsNone(anne.verified_on)
- # Run the workflow to model the confirmation step.
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- list(workflow)
- items = get_queue_messages('virgin', expected_count=1)
- message = items[0].msg
- token = workflow.token
- self.assertEqual(
- message['Subject'], 'confirm {}'.format(workflow.token))
- self.assertEqual(
- message['From'], 'test-confirm+{}@example.com'.format(token))
- # The state machine stopped at the moderator approval so there will be
- # one token still in the database.
- self._expected_pendings_count = 1
-
- def test_do_confirm_verify_address(self):
- # The address is not yet verified, nor are we pre-verifying. A
- # confirmation message will be sent. When the user confirms their
- # subscription request, the address will end up being verified.
- anne = self._user_manager.create_address(self._anne)
- self.assertIsNone(anne.verified_on)
- # Run the workflow to model the confirmation step.
- workflow = SubscriptionWorkflow(self._mlist, anne)
- list(workflow)
- # The address is still not verified.
- self.assertIsNone(anne.verified_on)
- confirm_workflow = SubscriptionWorkflow(self._mlist)
- confirm_workflow.token = workflow.token
- confirm_workflow.restore()
- confirm_workflow.run_thru('do_confirm_verify')
- # The address is now verified.
- self.assertIsNotNone(anne.verified_on)
-
- def test_do_confirm_verify_user(self):
- # A confirmation step is necessary when a user subscribes with their
- # preferred address, and we are not pre-confirming.
- anne = self._user_manager.create_user(self._anne)
- set_preferred(anne)
- # Run the workflow to model the confirmation step. There is no
- # subscriber attribute yet.
- workflow = SubscriptionWorkflow(self._mlist, anne)
- list(workflow)
- self.assertEqual(workflow.subscriber, anne)
- # Do a confirmation workflow, which should now set the subscriber.
- confirm_workflow = SubscriptionWorkflow(self._mlist)
- confirm_workflow.token = workflow.token
- confirm_workflow.restore()
- confirm_workflow.run_thru('do_confirm_verify')
- # The address is now verified.
- self.assertEqual(confirm_workflow.subscriber, anne)
-
- def test_do_confirmation_subscribes_user(self):
- # Subscriptions to the mailing list must be confirmed. Once that's
- # done, the user's address (which is not initially verified) gets
- # subscribed to the mailing list.
- self._mlist.subscription_policy = SubscriptionPolicy.confirm
- anne = self._user_manager.create_address(self._anne)
- self.assertIsNone(anne.verified_on)
- workflow = SubscriptionWorkflow(self._mlist, anne)
- list(workflow)
- # Anne is not yet a member.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertIsNone(member)
- self.assertIsNone(workflow.member)
- # The token is owned by the subscriber.
- self.assertIsNotNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.subscriber)
- # Confirm.
- confirm_workflow = SubscriptionWorkflow(self._mlist)
- confirm_workflow.token = workflow.token
- confirm_workflow.restore()
- list(confirm_workflow)
- self.assertIsNotNone(anne.verified_on)
- # Anne is now a member.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address, anne)
- self.assertEqual(confirm_workflow.member, member)
- # No further token is needed.
- self.assertIsNone(confirm_workflow.token)
- self.assertEqual(confirm_workflow.token_owner, TokenOwner.no_one)
-
- def test_prevent_confirmation_replay_attacks(self):
- # Ensure that if the workflow requires two confirmations, e.g. first
- # the user confirming their subscription, and then the moderator
- # approving it, that different tokens are used in these two cases.
- self._mlist.subscription_policy = (
- SubscriptionPolicy.confirm_then_moderate)
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- # Run the state machine up to the first confirmation, and cache the
- # confirmation token.
- list(workflow)
- token = workflow.token
- # Anne is not yet a member of the mailing list.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertIsNone(member)
- self.assertIsNone(workflow.member)
- # The token is owned by the subscriber.
- self.assertIsNotNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.subscriber)
- # The old token will not work for moderator approval.
- moderator_workflow = SubscriptionWorkflow(self._mlist)
- moderator_workflow.token = token
- moderator_workflow.restore()
- list(moderator_workflow)
- # The token is owned by the moderator.
- self.assertIsNotNone(moderator_workflow.token)
- self.assertEqual(moderator_workflow.token_owner, TokenOwner.moderator)
- # While we wait for the moderator to approve the subscription, note
- # that there's a new token for the next steps.
- self.assertNotEqual(token, moderator_workflow.token)
- # The old token won't work.
- final_workflow = SubscriptionWorkflow(self._mlist)
- final_workflow.token = token
- self.assertRaises(LookupError, final_workflow.restore)
- # Running this workflow will fail.
- self.assertRaises(AssertionError, list, final_workflow)
- # Anne is still not subscribed.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertIsNone(member)
- self.assertIsNone(final_workflow.member)
- # However, if we use the new token, her subscription request will be
- # approved by the moderator.
- final_workflow.token = moderator_workflow.token
- final_workflow.restore()
- list(final_workflow)
- # And now Anne is a member.
- member = self._mlist.regular_members.get_member(self._anne)
- self.assertEqual(member.address.email, self._anne)
- self.assertEqual(final_workflow.member, member)
- # No further token is needed.
- self.assertIsNone(final_workflow.token)
- self.assertEqual(final_workflow.token_owner, TokenOwner.no_one)
-
- def test_confirmation_needed_and_pre_confirmed(self):
- # The subscription policy is 'confirm' but the subscription is
- # pre-confirmed so the moderation checks can be skipped.
- self._mlist.subscription_policy = SubscriptionPolicy.confirm
- anne = self._user_manager.create_address(self._anne)
- workflow = SubscriptionWorkflow(
- self._mlist, anne,
- pre_verified=True, pre_confirmed=True, pre_approved=True)
- list(workflow)
- # Anne was subscribed.
- self.assertIsNone(workflow.token)
- self.assertEqual(workflow.token_owner, TokenOwner.no_one)
- self.assertEqual(workflow.member.address, anne)
-
- def test_restore_user_absorbed(self):
- # The subscribing user is absorbed (and thus deleted) before the
- # moderator approves the subscription.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_user(self._anne)
- bill = self._user_manager.create_user('bill@example.com')
- set_preferred(bill)
- # anne subscribes.
- workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
- list(workflow)
- # bill absorbs anne.
- bill.absorb(anne)
- # anne's subscription request is approved.
- approved_workflow = SubscriptionWorkflow(self._mlist)
- approved_workflow.token = workflow.token
- approved_workflow.restore()
- self.assertEqual(approved_workflow.user, bill)
- # Run the workflow through.
- list(approved_workflow)
-
- def test_restore_address_absorbed(self):
- # The subscribing user is absorbed (and thus deleted) before the
- # moderator approves the subscription.
- self._mlist.subscription_policy = SubscriptionPolicy.moderate
- anne = self._user_manager.create_user(self._anne)
- anne_address = anne.addresses[0]
- bill = self._user_manager.create_user('bill@example.com')
- # anne subscribes.
- workflow = SubscriptionWorkflow(
- self._mlist, anne_address, pre_verified=True)
- list(workflow)
- # bill absorbs anne.
- bill.absorb(anne)
- self.assertIn(anne_address, bill.addresses)
- # anne's subscription request is approved.
- approved_workflow = SubscriptionWorkflow(self._mlist)
- approved_workflow.token = workflow.token
- approved_workflow.restore()
- self.assertEqual(approved_workflow.user, bill)
- # Run the workflow through.
- list(approved_workflow)