summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2016-10-17 09:13:32 -0400
committerBarry Warsaw2016-10-17 09:13:32 -0400
commitd45af03c4f2a560d51631fdfa7c55cd1a98e722c (patch)
tree6cc33aa452d78c38a5d38e83855c5341f0422c2a /src
parent82a913bbf0e8772e7c98d5eb6160fe5b9f7f6f60 (diff)
downloadmailman-d45af03c4f2a560d51631fdfa7c55cd1a98e722c.tar.gz
mailman-d45af03c4f2a560d51631fdfa7c55cd1a98e722c.tar.zst
mailman-d45af03c4f2a560d51631fdfa7c55cd1a98e722c.zip
Simplify the implementation.
This merges the SubscriptionManager and UnsubscriptionManager into a single SubscriptionManager implementation that handles both register() and unregister(). This allows us to use direct class-based adaptation instead of the more clunky getAdapter() API. We can also eliminate the funky _get_workflow() implementation detail. This has a couple of side-effects. .confirm() must lookup the token in the pendings database and pull out the pending type, dispatching to the proper class depending on the type, or raising a LookupError if the token is None or there is no pendable associated with the given token. This feels like an acceptable trade-off. However, this *also* means that IWorkflowStateManager must lose its 'name' argument in its methods. That's because we won't actually know the name until its too late. Honestly, the name wasn't providing much value anyway (it was always the subclass's name), so losing that seems fine too. The complication here is that the name was a primary key in the 'workflowstate' table, so we need to add its removal in the database migration.
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/docs/moderator.rst4
-rw-r--r--src/mailman/app/subscriptions.py86
-rw-r--r--src/mailman/app/tests/test_moderation.py5
-rw-r--r--src/mailman/app/tests/test_subscriptions.py9
-rw-r--r--src/mailman/app/tests/test_unsubscriptions.py13
-rw-r--r--src/mailman/app/tests/test_workflowmanager.py5
-rw-r--r--src/mailman/app/workflow.py8
-rw-r--r--src/mailman/commands/eml_confirm.py5
-rw-r--r--src/mailman/commands/eml_membership.py7
-rw-r--r--src/mailman/commands/tests/test_confirm.py10
-rw-r--r--src/mailman/config/configure.zcml8
-rw-r--r--src/mailman/database/alembic/versions/448a93984c35_unsubscription_workflow.py5
-rw-r--r--src/mailman/interfaces/workflow.py14
-rw-r--r--src/mailman/model/docs/subscriptions.rst5
-rw-r--r--src/mailman/model/pending.py4
-rw-r--r--src/mailman/model/tests/test_workflow.py78
-rw-r--r--src/mailman/model/workflow.py13
-rw-r--r--src/mailman/rest/members.py5
-rw-r--r--src/mailman/rest/sub_moderation.py5
-rw-r--r--src/mailman/rest/tests/test_membership.py8
-rw-r--r--src/mailman/rest/tests/test_moderation.py5
-rw-r--r--src/mailman/runners/docs/command.rst3
-rw-r--r--src/mailman/runners/tests/test_confirm.py5
-rw-r--r--src/mailman/runners/tests/test_join.py6
24 files changed, 112 insertions, 204 deletions
diff --git a/src/mailman/app/docs/moderator.rst b/src/mailman/app/docs/moderator.rst
index e183d050c..ce25a4711 100644
--- a/src/mailman/app/docs/moderator.rst
+++ b/src/mailman/app/docs/moderator.rst
@@ -217,12 +217,12 @@ the unsubscribing address is required.
Fred is a member of the mailing list...
>>> from mailman.interfaces.usermanager import IUserManager
- >>> from zope.component import getAdapter, getUtility
+ >>> from zope.component import getUtility
>>> mlist.send_welcome_message = False
>>> fred = getUtility(IUserManager).create_address(
... 'fred@example.com', 'Fred Person')
>>> from mailman.interfaces.subscriptions import ISubscriptionManager
- >>> registrar = getAdapter(mlist, ISubscriptionManager, name='subscribe')
+ >>> registrar = ISubscriptionManager(mlist)
>>> token, token_owner, member = registrar.register(
... fred, pre_verified=True, pre_confirmed=True, pre_approved=True)
>>> member
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index 2790a6751..15df6b3f3 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -297,7 +297,9 @@ class SubscriptionWorkflow(Workflow):
# We can immediately subscribe the user to the mailing list.
self.member = self.mlist.subscribe(self.subscriber)
# This workflow is done so throw away any associated state.
- getUtility(IWorkflowStateManager).restore(self.name, self.token)
+ if self.token is not None:
+ getUtility(IWorkflowStateManager).discard(self.token)
+ self._set_token(TokenOwner.no_one)
def _step_send_confirmation(self):
self._set_token(TokenOwner.subscriber)
@@ -533,7 +535,9 @@ class UnSubscriptionWorkflow(Workflow):
pass
self.member = None
# This workflow is done so throw away any associated state.
- getUtility(IWorkflowStateManager).restore(self.name, self.token)
+ if self.token is not None:
+ getUtility(IWorkflowStateManager).discard(self.token)
+ self._set_token(TokenOwner.no_one)
def _step_unsubscribe_from_restored(self):
# Prevent replay attacks.
@@ -546,48 +550,11 @@ class UnSubscriptionWorkflow(Workflow):
self.push('do_unsubscription')
-class BaseSubscriptionManager:
- """Base class to handle registration and un-registration workflows."""
-
- def __init__(self, mlist):
- self._mlist = mlist
-
- def _get_workflow(self):
- raise NotImplementedError
-
- def register(self, subscriber=None, *,
- pre_verified=False, pre_confirmed=False, pre_approved=False):
- raise NotImplementedError
-
- def unregister(self, subscriber=None, *,
- pre_confirmed=False, pre_approved=False):
- raise NotImplementedError
-
- def confirm(self, token):
- workflow = self._get_workflow()
- workflow.token = token
- workflow.restore()
- # In order to just run the whole workflow, all we need to do
- # is iterate over the workflow object. On calling the __next__
- # over the workflow iterator it automatically executes the steps
- # that needs to be done.
- list(workflow)
- return workflow.token, workflow.token_owner, workflow.member
-
- def discard(self, token):
- with flush():
- getUtility(IPendings).confirm(token)
- getUtility(IWorkflowStateManager).discard(
- self._get_workflow().name, token)
-
-
@public
@implementer(ISubscriptionManager)
-class SubscriptionManager(BaseSubscriptionManager):
- """Handle registrations and confirmations for subscriptions."""
-
- def _get_workflow(self):
- return SubscriptionWorkflow(self._mlist)
+class SubscriptionManager:
+ def __init__(self, mlist):
+ self._mlist = mlist
def register(self, subscriber=None, *,
pre_verified=False, pre_confirmed=False, pre_approved=False):
@@ -600,15 +567,6 @@ class SubscriptionManager(BaseSubscriptionManager):
list(workflow)
return workflow.token, workflow.token_owner, workflow.member
-
-@public
-@implementer(ISubscriptionManager)
-class UnsubscriptionManager(BaseSubscriptionManager):
- """Handle un-subscriptions and confirmations for un-subscriptions."""
-
- def _get_workflow(self):
- return UnSubscriptionWorkflow(self._mlist)
-
def unregister(self, subscriber=None, *,
pre_confirmed=False, pre_approved=False):
workflow = UnSubscriptionWorkflow(
@@ -618,6 +576,32 @@ class UnsubscriptionManager(BaseSubscriptionManager):
list(workflow)
return workflow.token, workflow.token_owner, workflow.member
+ def confirm(self, token):
+ if token is None:
+ raise LookupError
+ pendable = getUtility(IPendings).confirm(token, expunge=False)
+ if pendable is None:
+ raise LookupError
+ workflow_type = pendable.get('type')
+ assert workflow_type in (PendableSubscription.PEND_TYPE,
+ PendableUnsubscription.PEND_TYPE)
+ workflow = (SubscriptionWorkflow
+ if workflow_type == PendableSubscription.PEND_TYPE
+ else UnSubscriptionWorkflow)(self._mlist)
+ workflow.token = token
+ workflow.restore()
+ # In order to just run the whole workflow, all we need to do
+ # is iterate over the workflow object. On calling the __next__
+ # over the workflow iterator it automatically executes the steps
+ # that needs to be done.
+ list(workflow)
+ return workflow.token, workflow.token_owner, workflow.member
+
+ def discard(self, token):
+ with flush():
+ getUtility(IPendings).confirm(token)
+ getUtility(IWorkflowStateManager).discard(token)
+
def _handle_confirmation_needed_events(event, template_name):
subject = 'confirm {}'.format(event.token)
diff --git a/src/mailman/app/tests/test_moderation.py b/src/mailman/app/tests/test_moderation.py
index 63b665948..90485bfad 100644
--- a/src/mailman/app/tests/test_moderation.py
+++ b/src/mailman/app/tests/test_moderation.py
@@ -35,7 +35,7 @@ from mailman.testing.helpers import (
specialized_message_from_string as mfs)
from mailman.testing.layers import SMTPLayer
from mailman.utilities.datetime import now
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class TestModeration(unittest.TestCase):
@@ -153,8 +153,7 @@ class TestUnsubscription(unittest.TestCase):
def setUp(self):
self._mlist = create_list('test@example.com')
- self._registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ self._registrar = ISubscriptionManager(self._mlist)
def test_unsubscribe_defer(self):
# When unsubscriptions must be approved by the moderator, but the
diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py
index 9f02593a9..a6a00d80e 100644
--- a/src/mailman/app/tests/test_subscriptions.py
+++ b/src/mailman/app/tests/test_subscriptions.py
@@ -359,8 +359,6 @@ class TestSubscriptionWorkflow(unittest.TestCase):
pre_verified=True,
pre_confirmed=True,
pre_approved=True)
- # Cache the token.
- token = workflow.token
# Consume the entire state machine.
list(workflow)
# Anne is now a member of the mailing list.
@@ -370,13 +368,6 @@ class TestSubscriptionWorkflow(unittest.TestCase):
# The workflow is done, so it has no token.
self.assertIsNone(workflow.token)
self.assertEqual(workflow.token_owner, TokenOwner.no_one)
- # The pendable associated with the token has been evicted.
- self.assertIsNone(getUtility(IPendings).confirm(token, expunge=False))
- # There is no saved workflow associated with the token. This shows up
- # as an exception when we try to restore the workflow.
- new_workflow = SubscriptionWorkflow(self._mlist)
- new_workflow.token = token
- self.assertRaises(LookupError, new_workflow.restore)
def test_moderator_approves(self):
# The workflow runs until moderator approval is required, at which
diff --git a/src/mailman/app/tests/test_unsubscriptions.py b/src/mailman/app/tests/test_unsubscriptions.py
index b7693f774..d8dbc18cb 100644
--- a/src/mailman/app/tests/test_unsubscriptions.py
+++ b/src/mailman/app/tests/test_unsubscriptions.py
@@ -184,7 +184,7 @@ class TestUnSubscriptionWorkflow(unittest.TestCase):
self.assertIsNone(workflow.token)
self.assertEqual(workflow.token_owner, TokenOwner.no_one)
- def test_do_unsubscription_pre_approved_pre_onfirmed(self):
+ def test_do_unsubscription_pre_approved_pre_confirmed(self):
# A moderation-requiring un-subscription policy plus a pre-appvoed
# address means the user gets un-subscribed to the mailing list without
# any further confirmations or approvals.
@@ -201,14 +201,12 @@ class TestUnSubscriptionWorkflow(unittest.TestCase):
self.assertEqual(workflow.token_owner, TokenOwner.no_one)
def test_do_unsubscription_cleanups(self):
- # Once the user is un-subscribed, the token and its associated pending
+ # Once the user is unsubscribed, the token and its associated pending
# database record will be removed from the database.
self._mlist.unsubscription_policy = SubscriptionPolicy.open
workflow = UnSubscriptionWorkflow(self._mlist, self.anne,
pre_approved=True,
pre_confirmed=True)
- # Cache the token.
- token = workflow.token
# Run the workflow.
list(workflow)
# Anne is now un-subscribed from the list.
@@ -217,13 +215,6 @@ class TestUnSubscriptionWorkflow(unittest.TestCase):
# Workflow is done, so it has no token.
self.assertIsNone(workflow.token)
self.assertEqual(workflow.token_owner, TokenOwner.no_one)
- # The pendable associated with the token as been evicted.
- self.assertIsNone(getUtility(IPendings).confirm(token, expunge=False))
- # There is no workflow associated with the token. This shows up as an
- # exception when trying to restore the workflow.
- new_workflow = UnSubscriptionWorkflow(self._mlist)
- new_workflow.token = token
- self.assertRaises(LookupError, new_workflow.restore)
def test_moderator_approves(self):
# The workflow runs until moderator approval is required, at which
diff --git a/src/mailman/app/tests/test_workflowmanager.py b/src/mailman/app/tests/test_workflowmanager.py
index f72486111..4193beefe 100644
--- a/src/mailman/app/tests/test_workflowmanager.py
+++ b/src/mailman/app/tests/test_workflowmanager.py
@@ -28,7 +28,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.testing.helpers import get_queue_messages
from mailman.testing.layers import ConfigLayer
from mailman.utilities.datetime import now
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class TestRegistrar(unittest.TestCase):
@@ -38,8 +38,7 @@ class TestRegistrar(unittest.TestCase):
def setUp(self):
self._mlist = create_list('ant@example.com')
- self._registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ self._registrar = ISubscriptionManager(self._mlist)
self._pendings = getUtility(IPendings)
self._anne = getUtility(IUserManager).create_address(
'anne@example.com')
diff --git a/src/mailman/app/workflow.py b/src/mailman/app/workflow.py
index eec8a14a8..762b0fd91 100644
--- a/src/mailman/app/workflow.py
+++ b/src/mailman/app/workflow.py
@@ -132,15 +132,11 @@ class Workflow:
raise AssertionError(
"Can't save a workflow state with more than one step "
"in the queue")
- state_manager.save(
- self.__class__.__name__,
- self.token,
- step,
- json.dumps(data))
+ state_manager.save(self.token, step, json.dumps(data))
def restore(self):
state_manager = getUtility(IWorkflowStateManager)
- state = state_manager.restore(self.__class__.__name__, self.token)
+ state = state_manager.restore(self.token)
if state is None:
# The token doesn't exist in the database.
raise LookupError(self.token)
diff --git a/src/mailman/commands/eml_confirm.py b/src/mailman/commands/eml_confirm.py
index b8e1610c4..6787b0987 100644
--- a/src/mailman/commands/eml_confirm.py
+++ b/src/mailman/commands/eml_confirm.py
@@ -21,7 +21,6 @@ from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
from mailman.interfaces.subscriptions import ISubscriptionManager, TokenOwner
-from zope.component import getAdapter
from zope.interface import implementer
@@ -50,8 +49,8 @@ class Confirm:
tokens.add(token)
results.confirms = tokens
try:
- new_token, token_owner, member = getAdapter(
- mlist, ISubscriptionManager, name='subscribe').confirm(token)
+ new_token, token_owner, member = ISubscriptionManager(
+ mlist).confirm(token)
if new_token is None:
assert token_owner is TokenOwner.no_one, token_owner
assert member is not None, member
diff --git a/src/mailman/commands/eml_membership.py b/src/mailman/commands/eml_membership.py
index 2c535a9d5..e658e7b58 100644
--- a/src/mailman/commands/eml_membership.py
+++ b/src/mailman/commands/eml_membership.py
@@ -25,7 +25,7 @@ from mailman.interfaces.member import DeliveryMode, MemberRole
from mailman.interfaces.subscriptions import (
ISubscriptionManager, ISubscriptionService)
from mailman.interfaces.usermanager import IUserManager
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
from zope.interface import implementer
@@ -101,8 +101,7 @@ used.
print(_('$person is already a member'), file=results)
return ContinueProcessing.yes
subscriber = match_subscriber(email, display_name)
- getAdapter(
- mlist, ISubscriptionManager, name='subscribe').register(subscriber)
+ ISubscriptionManager(mlist).register(subscriber)
print(_('Confirmation email sent to $person'), file=results)
return ContinueProcessing.yes
@@ -197,7 +196,7 @@ You may be asked to confirm your request.""")
return ContinueProcessing.yes
# Ignore any subsequent 'leave' commands.
already_left.add(email)
- manager = getAdapter(mlist, ISubscriptionManager, name='unsubscribe')
+ manager = ISubscriptionManager(mlist)
token, token_owner, member = manager.unregister(user_address)
person = formataddr((user.display_name, email)) # noqa
if member is None:
diff --git a/src/mailman/commands/tests/test_confirm.py b/src/mailman/commands/tests/test_confirm.py
index 7351bd6b7..e0f816f24 100644
--- a/src/mailman/commands/tests/test_confirm.py
+++ b/src/mailman/commands/tests/test_confirm.py
@@ -30,7 +30,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.runners.command import CommandRunner, Results
from mailman.testing.helpers import get_queue_messages, make_testable_runner
from mailman.testing.layers import ConfigLayer
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class TestConfirm(unittest.TestCase):
@@ -42,8 +42,8 @@ class TestConfirm(unittest.TestCase):
self._mlist = create_list('test@example.com')
anne = getUtility(IUserManager).create_address(
'anne@example.com', 'Anne Person')
- self._token, token_owner, member = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe').register(anne)
+ self._token, token_owner, member = ISubscriptionManager(
+ self._mlist).register(anne)
self._command = Confirm()
# Clear the virgin queue.
get_queue_messages('virgin')
@@ -88,8 +88,8 @@ class TestEmailResponses(unittest.TestCase):
'bart@example.com', 'Bart Person')
# Clear any previously queued confirmation messages.
get_queue_messages('virgin')
- self._token, token_owner, member = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe').register(bart)
+ self._token, token_owner, member = ISubscriptionManager(
+ self._mlist).register(bart)
# There should now be one email message in the virgin queue, i.e. the
# confirmation message sent to Bart.
items = get_queue_messages('virgin', expected_count=1)
diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml
index 338f02e1c..2fd0c8788 100644
--- a/src/mailman/config/configure.zcml
+++ b/src/mailman/config/configure.zcml
@@ -50,14 +50,6 @@
for="mailman.interfaces.mailinglist.IMailingList"
provides="mailman.interfaces.subscriptions.ISubscriptionManager"
factory="mailman.app.subscriptions.SubscriptionManager"
- name='subscribe'
- />
-
- <adapter
- for="mailman.interfaces.mailinglist.IMailingList"
- provides="mailman.interfaces.subscriptions.ISubscriptionManager"
- factory="mailman.app.subscriptions.UnsubscriptionManager"
- name='unsubscribe'
/>
<utility
diff --git a/src/mailman/database/alembic/versions/448a93984c35_unsubscription_workflow.py b/src/mailman/database/alembic/versions/448a93984c35_unsubscription_workflow.py
index 85003bd1e..dc57c8aee 100644
--- a/src/mailman/database/alembic/versions/448a93984c35_unsubscription_workflow.py
+++ b/src/mailman/database/alembic/versions/448a93984c35_unsubscription_workflow.py
@@ -9,7 +9,7 @@ import sqlalchemy as sa
from alembic import op
from mailman.database.helpers import exists_in_db
-from mailman.database.types import Enum
+from mailman.database.types import Enum, SAUnicode
from mailman.interfaces.mailinglist import SubscriptionPolicy
@@ -35,8 +35,11 @@ def upgrade():
op.execute(mlist.update().values(
{'unsubscription_policy':
op.inline_literal(SubscriptionPolicy.open)}))
+ with op.batch_alter_table('workflowstate') as batch_op:
+ batch_op.drop_column('name')
def downgrade():
with op.batch_alter_table('mailinglist') as batch_op:
batch_op.drop_column('unsubscription_policy')
+ op.add_column('workflowstate', sa.Column('name', SAUnicode))
diff --git a/src/mailman/interfaces/workflow.py b/src/mailman/interfaces/workflow.py
index bf2138959..9846f4683 100644
--- a/src/mailman/interfaces/workflow.py
+++ b/src/mailman/interfaces/workflow.py
@@ -25,8 +25,6 @@ from zope.interface import Attribute, Interface
class IWorkflowState(Interface):
"""The state of a workflow."""
- name = Attribute('The name of the workflow.')
-
token = Attribute('A unique key identifying the workflow instance.')
step = Attribute("This workflow's next step.")
@@ -38,11 +36,9 @@ class IWorkflowState(Interface):
class IWorkflowStateManager(Interface):
"""The workflow states manager."""
- def save(name, token, step, data=None):
+ def save(token, step, data=None):
"""Save the state of a workflow.
- :param name: The name of the workflow.
- :type name: str
:param token: A unique token identifying this workflow instance.
:type token: str
:param step: The next step for this workflow.
@@ -51,11 +47,9 @@ class IWorkflowStateManager(Interface):
:type data: str
"""
- def restore(name, token):
+ def restore(token):
"""Get the saved state for a workflow or None if nothing was saved.
- :param name: The name of the workflow.
- :type name: str
:param token: A unique token identifying this workflow instance.
:type token: str
:return: The saved state associated with this name/token pair, or None
@@ -63,11 +57,9 @@ class IWorkflowStateManager(Interface):
:rtype: ``IWorkflowState``
"""
- def discard(name, token):
+ def discard(token):
"""Throw away the saved state for a workflow.
- :param name: The name of the workflow.
- :type name: str
:param token: A unique token identifying this workflow instance.
:type token: str
"""
diff --git a/src/mailman/model/docs/subscriptions.rst b/src/mailman/model/docs/subscriptions.rst
index 4c079d542..1e1810a7a 100644
--- a/src/mailman/model/docs/subscriptions.rst
+++ b/src/mailman/model/docs/subscriptions.rst
@@ -13,9 +13,8 @@ To begin, adapt a mailing list to an ``ISubscriptionManager``. This is a
named interface because the same interface manages both subscriptions and
unsubscriptions.
- >>> from zope.component import getAdapter
>>> mlist = create_list('ant@example.com')
- >>> manager = getAdapter(mlist, ISubscriptionManager, 'subscribe')
+ >>> manager = ISubscriptionManager(mlist)
Either addresses or users with a preferred address can be registered.
@@ -114,7 +113,7 @@ that their email address is already verified, that step is not required. To
begin with unsubscribing, you need to adapt the mailing list to the same
interface, but with a different name.
- >>> manager = getAdapter(mlist, ISubscriptionManager, 'unsubscribe')
+ >>> manager = ISubscriptionManager(mlist)
If the mailing list's unsubscription policy is open, unregistering the
subscription takes effect immediately.
diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py
index 9d8315605..7e7f0b2eb 100644
--- a/src/mailman/model/pending.py
+++ b/src/mailman/model/pending.py
@@ -130,8 +130,8 @@ class Pendings:
# Iterate on PendedKeyValue entries that are associated with the
# pending object's ID. Watch out for type conversions.
for keyvalue in pending.key_values:
- # The `type` key is special and served. It is not JSONified. See
- # the IPendable interface for details.
+ # The `type` key is special and reserved. It is not JSONified.
+ # See the IPendable interface for details.
if keyvalue.key == 'type':
value = keyvalue.value
else:
diff --git a/src/mailman/model/tests/test_workflow.py b/src/mailman/model/tests/test_workflow.py
index ee14f17a7..6aade980b 100644
--- a/src/mailman/model/tests/test_workflow.py
+++ b/src/mailman/model/tests/test_workflow.py
@@ -32,116 +32,88 @@ class TestWorkflow(unittest.TestCase):
def test_save_restore_workflow(self):
# Save and restore a workflow.
- name = 'ant'
token = 'bee'
step = 'cat'
data = 'dog'
- self._manager.save(name, token, step, data)
- state = self._manager.restore(name, token)
- self.assertEqual(state.name, name)
+ self._manager.save(token, step, data)
+ state = self._manager.restore(token)
self.assertEqual(state.token, token)
self.assertEqual(state.step, step)
self.assertEqual(state.data, data)
def test_save_restore_workflow_without_step(self):
# Save and restore a workflow that contains no step.
- name = 'ant'
token = 'bee'
data = 'dog'
- self._manager.save(name, token, data=data)
- state = self._manager.restore(name, token)
- self.assertEqual(state.name, name)
+ self._manager.save(token, data=data)
+ state = self._manager.restore(token)
self.assertEqual(state.token, token)
self.assertIsNone(state.step)
self.assertEqual(state.data, data)
def test_save_restore_workflow_without_data(self):
# Save and restore a workflow that contains no data.
- name = 'ant'
token = 'bee'
step = 'cat'
- self._manager.save(name, token, step)
- state = self._manager.restore(name, token)
- self.assertEqual(state.name, name)
+ self._manager.save(token, step)
+ state = self._manager.restore(token)
self.assertEqual(state.token, token)
self.assertEqual(state.step, step)
self.assertIsNone(state.data)
def test_save_restore_workflow_without_step_or_data(self):
# Save and restore a workflow that contains no step or data.
- name = 'ant'
token = 'bee'
- self._manager.save(name, token)
- state = self._manager.restore(name, token)
- self.assertEqual(state.name, name)
+ self._manager.save(token)
+ state = self._manager.restore(token)
self.assertEqual(state.token, token)
self.assertIsNone(state.step)
self.assertIsNone(state.data)
- def test_restore_workflow_with_no_matching_name(self):
- # Try to restore a workflow that has no matching name in the database.
- name = 'ant'
- token = 'bee'
- self._manager.save(name, token)
- state = self._manager.restore('ewe', token)
- self.assertIsNone(state)
-
def test_restore_workflow_with_no_matching_token(self):
# Try to restore a workflow that has no matching token in the database.
- name = 'ant'
- token = 'bee'
- self._manager.save(name, token)
- state = self._manager.restore(name, 'fly')
- self.assertIsNone(state)
-
- def test_restore_workflow_with_no_matching_token_or_name(self):
- # Try to restore a workflow that has no matching token or name in the
- # database.
- name = 'ant'
token = 'bee'
- self._manager.save(name, token)
- state = self._manager.restore('ewe', 'fly')
+ self._manager.save(token)
+ state = self._manager.restore('fly')
self.assertIsNone(state)
def test_restore_removes_record(self):
- name = 'ant'
token = 'bee'
self.assertEqual(self._manager.count, 0)
- self._manager.save(name, token)
+ self._manager.save(token)
self.assertEqual(self._manager.count, 1)
- self._manager.restore(name, token)
+ self._manager.restore(token)
self.assertEqual(self._manager.count, 0)
def test_save_after_restore(self):
- name = 'ant'
token = 'bee'
self.assertEqual(self._manager.count, 0)
- self._manager.save(name, token)
+ self._manager.save(token)
self.assertEqual(self._manager.count, 1)
- self._manager.restore(name, token)
+ self._manager.restore(token)
self.assertEqual(self._manager.count, 0)
- self._manager.save(name, token)
+ self._manager.save(token)
self.assertEqual(self._manager.count, 1)
def test_discard(self):
# Discard some workflow state. This is use by
# ISubscriptionManager.discard().
- self._manager.save('ant', 'token', 'one')
- self._manager.save('bee', 'token', 'two')
- self._manager.save('ant', 'nekot', 'three')
- self._manager.save('bee', 'nekot', 'four')
+ self._manager.save('token1', 'one')
+ self._manager.save('token2', 'two')
+ self._manager.save('token3', 'three')
+ self._manager.save('token4', 'four')
self.assertEqual(self._manager.count, 4)
- self._manager.discard('bee', 'token')
+ self._manager.discard('token2')
self.assertEqual(self._manager.count, 3)
- state = self._manager.restore('ant', 'token')
+ state = self._manager.restore('token1')
self.assertEqual(state.step, 'one')
- state = self._manager.restore('bee', 'token')
+ state = self._manager.restore('token2')
self.assertIsNone(state)
- state = self._manager.restore('ant', 'nekot')
+ state = self._manager.restore('token3')
self.assertEqual(state.step, 'three')
- state = self._manager.restore('bee', 'nekot')
+ state = self._manager.restore('token4')
self.assertEqual(state.step, 'four')
def test_discard_missing_workflow(self):
- self._manager.discard('bogus-name', 'bogus-token')
+ self._manager.discard('bogus-token')
self.assertEqual(self._manager.count, 0)
diff --git a/src/mailman/model/workflow.py b/src/mailman/model/workflow.py
index 1072fa548..53763a0e8 100644
--- a/src/mailman/model/workflow.py
+++ b/src/mailman/model/workflow.py
@@ -33,7 +33,6 @@ class WorkflowState(Model):
__tablename__ = 'workflowstate'
- name = Column(SAUnicode, primary_key=True)
token = Column(SAUnicode, primary_key=True)
step = Column(SAUnicode)
data = Column(SAUnicode)
@@ -45,23 +44,23 @@ class WorkflowStateManager:
"""See `IWorkflowStateManager`."""
@dbconnection
- def save(self, store, name, token, step=None, data=None):
+ def save(self, store, token, step=None, data=None):
"""See `IWorkflowStateManager`."""
- state = WorkflowState(name=name, token=token, step=step, data=data)
+ state = WorkflowState(token=token, step=step, data=data)
store.add(state)
@dbconnection
- def restore(self, store, name, token):
+ def restore(self, store, token):
"""See `IWorkflowStateManager`."""
- state = store.query(WorkflowState).get((name, token))
+ state = store.query(WorkflowState).get(token)
if state is not None:
store.delete(state)
return state
@dbconnection
- def discard(self, store, name, token):
+ def discard(self, store, token):
"""See `IWorkflowStateManager`."""
- state = store.query(WorkflowState).get((name, token))
+ state = store.query(WorkflowState).get(token)
if state is not None:
store.delete(state)
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index fd9f141cc..b35440af4 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -37,7 +37,7 @@ from mailman.rest.preferences import Preferences, ReadOnlyPreferences
from mailman.rest.validator import (
Validator, enum_validator, subscriber_validator)
from uuid import UUID
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class _MemberBase(CollectionMixin):
@@ -253,8 +253,7 @@ class AllMembers(_MemberBase):
# Now we can run the registration process until either the
# subscriber is subscribed, or the workflow is paused for
# verification, confirmation, or approval.
- registrar = getAdapter(
- mlist, ISubscriptionManager, name='subscribe')
+ registrar = ISubscriptionManager(mlist)
try:
token, token_owner, member = registrar.register(
subscriber,
diff --git a/src/mailman/rest/sub_moderation.py b/src/mailman/rest/sub_moderation.py
index 273d4c3a0..55b6a7609 100644
--- a/src/mailman/rest/sub_moderation.py
+++ b/src/mailman/rest/sub_moderation.py
@@ -28,7 +28,7 @@ from mailman.rest.helpers import (
CollectionMixin, bad_request, child, conflict, etag, no_content,
not_found, okay)
from mailman.rest.validator import Validator, enum_validator
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class _ModerationBase:
@@ -54,8 +54,7 @@ class IndividualRequest(_ModerationBase):
def __init__(self, mlist, token):
super().__init__()
self._mlist = mlist
- self._registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ self._registrar = ISubscriptionManager(self._mlist)
self._token = token
def on_get(self, request, response):
diff --git a/src/mailman/rest/tests/test_membership.py b/src/mailman/rest/tests/test_membership.py
index 9e5a486f3..f705fdcf6 100644
--- a/src/mailman/rest/tests/test_membership.py
+++ b/src/mailman/rest/tests/test_membership.py
@@ -34,7 +34,7 @@ from mailman.testing.helpers import (
from mailman.testing.layers import ConfigLayer, RESTLayer
from mailman.utilities.datetime import now
from urllib.error import HTTPError
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class TestMembership(unittest.TestCase):
@@ -214,8 +214,7 @@ class TestMembership(unittest.TestCase):
def test_duplicate_pending_subscription(self):
# Issue #199 - a member's subscription is already pending and they try
# to subscribe again.
- registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ registrar = ISubscriptionManager(self._mlist)
with transaction():
self._mlist.subscription_policy = SubscriptionPolicy.moderate
anne = self._usermanager.create_address('anne@example.com')
@@ -238,8 +237,7 @@ class TestMembership(unittest.TestCase):
# Issue #199 - a member's subscription is already pending and they try
# to subscribe again. Unlike above, this pend is waiting for the user
# to confirm their subscription.
- registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ registrar = ISubscriptionManager(self._mlist)
with transaction():
self._mlist.subscription_policy = (
SubscriptionPolicy.confirm_then_moderate)
diff --git a/src/mailman/rest/tests/test_moderation.py b/src/mailman/rest/tests/test_moderation.py
index cbf9c9381..e0c3f1ccf 100644
--- a/src/mailman/rest/tests/test_moderation.py
+++ b/src/mailman/rest/tests/test_moderation.py
@@ -32,7 +32,7 @@ from mailman.testing.helpers import (
specialized_message_from_string as mfs)
from mailman.testing.layers import RESTLayer
from urllib.error import HTTPError
-from zope.component import getAdapter, getUtility
+from zope.component import getUtility
class TestPostModeration(unittest.TestCase):
@@ -150,8 +150,7 @@ class TestSubscriptionModeration(unittest.TestCase):
def setUp(self):
with transaction():
self._mlist = create_list('ant@example.com')
- self._registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ self._registrar = ISubscriptionManager(self._mlist)
manager = getUtility(IUserManager)
self._anne = manager.create_address(
'anne@example.com', 'Anne Person')
diff --git a/src/mailman/runners/docs/command.rst b/src/mailman/runners/docs/command.rst
index fec0d628b..2243d4ff4 100644
--- a/src/mailman/runners/docs/command.rst
+++ b/src/mailman/runners/docs/command.rst
@@ -141,9 +141,8 @@ address, and the other is the results of his email command.
2
>>> from mailman.interfaces.subscriptions import ISubscriptionManager
- >>> from zope.component import getAdapter
- >>> manager = getAdapter(mlist, ISubscriptionManager, 'subscribe')
+ >>> manager = ISubscriptionManager(mlist)
>>> for item in messages:
... subject = item.msg['subject']
... print('Subject:', subject)
diff --git a/src/mailman/runners/tests/test_confirm.py b/src/mailman/runners/tests/test_confirm.py
index bb18914d0..af6f03eb5 100644
--- a/src/mailman/runners/tests/test_confirm.py
+++ b/src/mailman/runners/tests/test_confirm.py
@@ -31,7 +31,7 @@ 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 getAdapter, getUtility
+from zope.component import getUtility
class TestConfirm(unittest.TestCase):
@@ -47,8 +47,7 @@ class TestConfirm(unittest.TestCase):
self._mlist = create_list('test@example.com')
self._mlist.send_welcome_message = False
anne = getUtility(IUserManager).create_address('anne@example.org')
- registrar = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe')
+ registrar = ISubscriptionManager(self._mlist)
self._token, token_owner, member = registrar.register(anne)
def test_confirm_with_re_prefix(self):
diff --git a/src/mailman/runners/tests/test_join.py b/src/mailman/runners/tests/test_join.py
index 1fb1dfe5c..1e249d68f 100644
--- a/src/mailman/runners/tests/test_join.py
+++ b/src/mailman/runners/tests/test_join.py
@@ -31,7 +31,7 @@ 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 getAdapter, getUtility
+from zope.component import getUtility
class TestJoin(unittest.TestCase):
@@ -145,8 +145,8 @@ class TestJoinWithDigests(unittest.TestCase):
subject_words = str(items[1].msg['subject']).split()
self.assertEqual(subject_words[0], 'confirm')
token = subject_words[1]
- token, token_owner, rmember = getAdapter(
- self._mlist, ISubscriptionManager, name='subscribe').confirm(token)
+ 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