summaryrefslogtreecommitdiff
path: root/src/mailman/model
diff options
context:
space:
mode:
authorJ08nY2017-08-07 19:00:49 +0200
committerJ08nY2017-08-07 19:00:49 +0200
commitee9da27283ffb7adc836f764f1442cd06e3fb2a5 (patch)
tree2b687f39714580b1de70baf9e3dd9957326c4989 /src/mailman/model
parentd107fd41f03b57f7731b60bb7ba921febc3ce3b9 (diff)
parentb902d7858d8302d248add89a5983c521c3581c4c (diff)
downloadmailman-plugin.tar.gz
mailman-plugin.tar.zst
mailman-plugin.zip
Diffstat (limited to 'src/mailman/model')
-rw-r--r--src/mailman/model/docs/subscriptions.rst13
-rw-r--r--src/mailman/model/mailinglist.py36
-rw-r--r--src/mailman/model/tests/test_mailinglist.py24
-rw-r--r--src/mailman/model/tests/test_workflow.py24
-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