diff options
| author | J08nY | 2017-08-07 19:00:49 +0200 |
|---|---|---|
| committer | J08nY | 2017-08-07 19:00:49 +0200 |
| commit | ee9da27283ffb7adc836f764f1442cd06e3fb2a5 (patch) | |
| tree | 2b687f39714580b1de70baf9e3dd9957326c4989 /src/mailman/model | |
| parent | d107fd41f03b57f7731b60bb7ba921febc3ce3b9 (diff) | |
| parent | b902d7858d8302d248add89a5983c521c3581c4c (diff) | |
| download | mailman-plugin.tar.gz mailman-plugin.tar.zst mailman-plugin.zip | |
Diffstat (limited to 'src/mailman/model')
| -rw-r--r-- | src/mailman/model/docs/subscriptions.rst | 13 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 36 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_mailinglist.py | 24 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_workflow.py | 24 | ||||
| -rw-r--r-- | src/mailman/model/workflows.py (renamed from src/mailman/model/workflow.py) | 8 |
5 files changed, 81 insertions, 24 deletions
diff --git a/src/mailman/model/docs/subscriptions.rst b/src/mailman/model/docs/subscriptions.rst index 1e1810a7a..e23236b3b 100644 --- a/src/mailman/model/docs/subscriptions.rst +++ b/src/mailman/model/docs/subscriptions.rst @@ -33,8 +33,8 @@ list's subscription policy. For example, an open subscription policy does not require confirmation or approval, but the email address must still be verified, and the process will pause until these steps are completed. - >>> from mailman.interfaces.mailinglist import SubscriptionPolicy - >>> mlist.subscription_policy = SubscriptionPolicy.open + >>> from mailman.workflows.subscription import OpenSubscriptionPolicy + >>> mlist.subscription_policy = OpenSubscriptionPolicy Anne attempts to join the mailing list. A unique token is created which represents this work flow. @@ -81,7 +81,8 @@ Bart verifies his address and makes it his preferred address. The mailing list's subscription policy does not require Bart to confirm his subscription, but the moderate does want to approve all subscriptions. - >>> mlist.subscription_policy = SubscriptionPolicy.moderate + >>> from mailman.workflows.subscription import ModerationSubscriptionPolicy + >>> mlist.subscription_policy = ModerationSubscriptionPolicy Now when Bart registers as a user for the mailing list, a token will still be generated, but this is only used by the moderator. At first, Bart is not @@ -118,7 +119,8 @@ interface, but with a different name. If the mailing list's unsubscription policy is open, unregistering the subscription takes effect immediately. - >>> mlist.unsubscription_policy = SubscriptionPolicy.open + >>> from mailman.workflows.unsubscription import OpenUnsubscriptionPolicy + >>> mlist.unsubscription_policy = OpenUnsubscriptionPolicy >>> token, token_owner, member = manager.unregister(anne) >>> print(mlist.members.get_member('anne@example.com')) None @@ -127,7 +129,8 @@ Usually though, the member must confirm their unsubscription request, to prevent an attacker from unsubscribing them from the list without their knowledge. - >>> mlist.unsubscription_policy = SubscriptionPolicy.confirm + >>> from mailman.workflows.unsubscription import ConfirmUnsubscriptionPolicy + >>> mlist.unsubscription_policy = ConfirmUnsubscriptionPolicy >>> token, token_owner, member = manager.unregister(bart) Bart hasn't confirmed yet, so he's still a member of the list. diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 2e50575d5..0764be0bb 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -34,13 +34,15 @@ from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.mailinglist import ( DMARCMitigateAction, IAcceptableAlias, IAcceptableAliasSet, IHeaderMatch, IHeaderMatchList, IListArchiver, IListArchiverSet, - IMailingList, Personalization, ReplyToMunging, SubscriptionPolicy) + IMailingList, Personalization, ReplyToMunging) from mailman.interfaces.member import ( AlreadySubscribedError, MemberRole, MissingPreferredAddressError, SubscriptionEvent) from mailman.interfaces.mime import FilterType from mailman.interfaces.nntp import NewsgroupModeration from mailman.interfaces.user import IUser +from mailman.interfaces.workflows import (ISubscriptionWorkflow, + IUnsubscriptionWorkflow) from mailman.model import roster from mailman.model.digests import OneLastDigest from mailman.model.member import Member @@ -179,11 +181,11 @@ class MailingList(Model): send_goodbye_message = Column(Boolean) send_welcome_message = Column(Boolean) subject_prefix = Column(SAUnicode) - subscription_policy = Column(Enum(SubscriptionPolicy)) + _subscription_policy = Column('subscription_policy', SAUnicode) topics = Column(PickleType) topics_bodylines_limit = Column(Integer) topics_enabled = Column(Boolean) - unsubscription_policy = Column(Enum(SubscriptionPolicy)) + _unsubscription_policy = Column('unsubscription_policy', SAUnicode) # ORM relationships. header_matches = relationship( 'HeaderMatch', backref='mailing_list', @@ -494,6 +496,34 @@ class MailingList(Model): notify(SubscriptionEvent(self, member)) return member + @property + def subscription_policy(self): + return config.workflows[self._subscription_policy] + + @subscription_policy.setter + def subscription_policy(self, value): + if isinstance(value, str): + cls = config.workflows.get(value, None) + else: + cls = value + if (cls is None or not ISubscriptionWorkflow.implementedBy(cls)): + raise ValueError('Invalid subscription policy: {}'.format(value)) + self._subscription_policy = cls.name + + @property + def unsubscription_policy(self): + return config.workflows[self._unsubscription_policy] + + @unsubscription_policy.setter + def unsubscription_policy(self, value): + if isinstance(value, str): + cls = config.workflows.get(value, None) + else: + cls = value + if (cls is None or not IUnsubscriptionWorkflow.implementedBy(cls)): + raise ValueError('Invalid unsubscription policy: {}'.format(value)) + self._unsubscription_policy = cls.name + @public @implementer(IAcceptableAlias) diff --git a/src/mailman/model/tests/test_mailinglist.py b/src/mailman/model/tests/test_mailinglist.py index 72232cb53..a402c6dc4 100644 --- a/src/mailman/model/tests/test_mailinglist.py +++ b/src/mailman/model/tests/test_mailinglist.py @@ -28,6 +28,8 @@ from mailman.interfaces.mailinglist import ( from mailman.interfaces.member import ( AlreadySubscribedError, MemberRole, MissingPreferredAddressError) from mailman.interfaces.usermanager import IUserManager +from mailman.interfaces.workflows import ( + ISubscriptionWorkflow, IUnsubscriptionWorkflow) from mailman.testing.helpers import ( configuration, get_queue_messages, set_preferred) from mailman.testing.layers import ConfigLayer @@ -408,3 +410,25 @@ class TestHeaderMatch(unittest.TestCase): header_matches = IHeaderMatchList(self._mlist) with self.assertRaises(IndexError): del header_matches[0] + + def test_subscription_policy(self): + for workflow_class in config.workflows: + if ISubscriptionWorkflow.implementedBy(workflow_class): + self._mlist.subscription_policy = workflow_class.name + self.assertEqual(self._mlist.subscription_policy, + workflow_class) + + def test_subscription_policy_invalid(self): + with self.assertRaises(ValueError): + self._mlist.subscription_policy = 'not-a-subscription-policy' + + def test_unsubscription_policy(self): + for workflow_class in config.workflows: + if IUnsubscriptionWorkflow.implementedBy(workflow_class): + self._mlist.unsubscription_policy = workflow_class.name + self.assertEqual(self._mlist.unsubscription_policy, + workflow_class) + + def test_unsubscription_policy_invalid(self): + with self.assertRaises(ValueError): + self._mlist.unsubscription_policy = 'not-an-unsubscription-policy' diff --git a/src/mailman/model/tests/test_workflow.py b/src/mailman/model/tests/test_workflow.py index 9cc5446b7..900efbb25 100644 --- a/src/mailman/model/tests/test_workflow.py +++ b/src/mailman/model/tests/test_workflow.py @@ -19,7 +19,7 @@ import unittest -from mailman.interfaces.workflow import IWorkflowStateManager +from mailman.interfaces.workflows import IWorkflowStateManager from mailman.testing.layers import ConfigLayer from zope.component import getUtility @@ -33,12 +33,12 @@ class TestWorkflow(unittest.TestCase): def test_save_restore_workflow(self): # Save and restore a workflow. token = 'bee' - step = 'cat' + steps = 'cat' data = 'dog' - self._manager.save(token, step, data) + self._manager.save(token, steps, data) state = self._manager.restore(token) self.assertEqual(state.token, token) - self.assertEqual(state.step, step) + self.assertEqual(state.steps, steps) self.assertEqual(state.data, data) def test_save_restore_workflow_without_step(self): @@ -48,17 +48,17 @@ class TestWorkflow(unittest.TestCase): self._manager.save(token, data=data) state = self._manager.restore(token) self.assertEqual(state.token, token) - self.assertIsNone(state.step) + self.assertIsNone(state.steps) self.assertEqual(state.data, data) def test_save_restore_workflow_without_data(self): # Save and restore a workflow that contains no data. token = 'bee' - step = 'cat' - self._manager.save(token, step) + steps = 'cat' + self._manager.save(token, steps) state = self._manager.restore(token) self.assertEqual(state.token, token) - self.assertEqual(state.step, step) + self.assertEqual(state.steps, steps) self.assertIsNone(state.data) def test_save_restore_workflow_without_step_or_data(self): @@ -67,7 +67,7 @@ class TestWorkflow(unittest.TestCase): self._manager.save(token) state = self._manager.restore(token) self.assertEqual(state.token, token) - self.assertIsNone(state.step) + self.assertIsNone(state.steps) self.assertIsNone(state.data) def test_restore_workflow_with_no_matching_token(self): @@ -106,13 +106,13 @@ class TestWorkflow(unittest.TestCase): self._manager.discard('token2') self.assertEqual(self._manager.count, 3) state = self._manager.restore('token1') - self.assertEqual(state.step, 'one') + self.assertEqual(state.steps, 'one') state = self._manager.restore('token2') self.assertIsNone(state) state = self._manager.restore('token3') - self.assertEqual(state.step, 'three') + self.assertEqual(state.steps, 'three') state = self._manager.restore('token4') - self.assertEqual(state.step, 'four') + self.assertEqual(state.steps, 'four') def test_discard_missing_workflow(self): self._manager.discard('bogus-token') diff --git a/src/mailman/model/workflow.py b/src/mailman/model/workflows.py index 3ca3412a6..be793eb43 100644 --- a/src/mailman/model/workflow.py +++ b/src/mailman/model/workflows.py @@ -20,7 +20,7 @@ from mailman.database.model import Model from mailman.database.transaction import dbconnection from mailman.database.types import SAUnicode -from mailman.interfaces.workflow import IWorkflowState, IWorkflowStateManager +from mailman.interfaces.workflows import IWorkflowState, IWorkflowStateManager from public import public from sqlalchemy import Column from zope.interface import implementer @@ -34,7 +34,7 @@ class WorkflowState(Model): __tablename__ = 'workflowstate' token = Column(SAUnicode, primary_key=True) - step = Column(SAUnicode) + steps = Column(SAUnicode) data = Column(SAUnicode) @@ -44,9 +44,9 @@ class WorkflowStateManager: """See `IWorkflowStateManager`.""" @dbconnection - def save(self, store, token, step=None, data=None): + def save(self, store, token, steps=None, data=None): """See `IWorkflowStateManager`.""" - state = WorkflowState(token=token, step=step, data=data) + state = WorkflowState(token=token, steps=steps, data=data) store.add(state) @dbconnection |
