summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/events.py3
-rw-r--r--src/mailman/app/moderator.py13
-rw-r--r--src/mailman/chains/docs/moderation.rst (renamed from src/mailman/chains/docs/moderation.txt)0
-rw-r--r--src/mailman/interfaces/listmanager.py16
-rw-r--r--src/mailman/model/docs/pending.rst (renamed from src/mailman/model/docs/pending.txt)0
-rw-r--r--src/mailman/model/listmanager.py5
-rw-r--r--src/mailman/model/tests/test_listmanager.py83
-rw-r--r--src/mailman/model/tests/test_member.py33
-rw-r--r--src/mailman/testing/helpers.py1
9 files changed, 110 insertions, 44 deletions
diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py
index 9cdeba797..ac318f6b2 100644
--- a/src/mailman/app/events.py
+++ b/src/mailman/app/events.py
@@ -27,12 +27,13 @@ __all__ = [
from zope import event
-from mailman.app import subscriptions
+from mailman.app import moderator, subscriptions
def initialize():
"""Initialize global event subscribers."""
event.subscribers.extend([
+ moderator.handle_ListDeletingEvent,
subscriptions.handle_ListDeletedEvent,
])
diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py
index 1b9f21d2a..0ba6f492a 100644
--- a/src/mailman/app/moderator.py
+++ b/src/mailman/app/moderator.py
@@ -21,6 +21,7 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
+ 'handle_ListDeletingEvent',
'handle_message',
'handle_subscription',
'handle_unsubscription',
@@ -43,6 +44,7 @@ from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.action import Action
from mailman.interfaces.languages import ILanguageManager
+from mailman.interfaces.listmanager import ListDeletingEvent
from mailman.interfaces.member import (
AlreadySubscribedError, DeliveryMode, NotAMemberError)
from mailman.interfaces.messages import IMessageStore
@@ -355,3 +357,14 @@ def _refuse(mlist, request, recip, comment, origmsg=None, lang=None):
subject = _('Request to mailing list "$realname" rejected')
msg = UserNotification(recip, mlist.bounces_address, subject, text, lang)
msg.send(mlist)
+
+
+
+def handle_ListDeletingEvent(event):
+ if not isinstance(event, ListDeletingEvent):
+ return
+ # Get the held requests database for the mailing list. Since the mailing
+ # list is about to get deleted, we can delete all associated requests.
+ requestsdb = getUtility(IRequests).get_list_requests(event.mailing_list)
+ for request in requestsdb.held_requests:
+ requestsdb.delete_request(request.id)
diff --git a/src/mailman/chains/docs/moderation.txt b/src/mailman/chains/docs/moderation.rst
index d80f9bd2c..d80f9bd2c 100644
--- a/src/mailman/chains/docs/moderation.txt
+++ b/src/mailman/chains/docs/moderation.rst
diff --git a/src/mailman/interfaces/listmanager.py b/src/mailman/interfaces/listmanager.py
index 3038be02b..c1b7721a9 100644
--- a/src/mailman/interfaces/listmanager.py
+++ b/src/mailman/interfaces/listmanager.py
@@ -24,7 +24,9 @@ __all__ = [
'IListManager',
'ListAlreadyExistsError',
'ListCreatedEvent',
+ 'ListCreatingEvent',
'ListDeletedEvent',
+ 'ListDeletingEvent',
'NoSuchListError',
]
@@ -53,6 +55,13 @@ class NoSuchListError(MailmanError):
return 'No such mailing list: {0.fqdn_listname}'.format(self)
+class ListCreatingEvent:
+ """A mailing list is about to be created."""
+
+ def __init__(self, fqdn_listname):
+ self.fqdn_listname = fqdn_listname
+
+
class ListCreatedEvent:
"""A mailing list was created."""
@@ -60,6 +69,13 @@ class ListCreatedEvent:
self.mailing_list = mlist
+class ListDeletingEvent:
+ """A mailing list is about to be deleted."""
+
+ def __init__(self, mailing_list):
+ self.mailing_list = mailing_list
+
+
class ListDeletedEvent:
"""A mailing list was deleted."""
diff --git a/src/mailman/model/docs/pending.txt b/src/mailman/model/docs/pending.rst
index 707e8a7fc..707e8a7fc 100644
--- a/src/mailman/model/docs/pending.txt
+++ b/src/mailman/model/docs/pending.rst
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index 8c3fc9421..16185e670 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -33,7 +33,8 @@ from zope.interface import implements
from mailman.config import config
from mailman.interfaces.address import InvalidEmailAddressError
from mailman.interfaces.listmanager import (
- IListManager, ListAlreadyExistsError, ListCreatedEvent, ListDeletedEvent)
+ IListManager, ListAlreadyExistsError, ListCreatedEvent, ListCreatingEvent,
+ ListDeletedEvent, ListDeletingEvent)
from mailman.model.mailinglist import MailingList
@@ -48,6 +49,7 @@ class ListManager:
listname, at, hostname = fqdn_listname.partition('@')
if len(hostname) == 0:
raise InvalidEmailAddressError(fqdn_listname)
+ notify(ListCreatingEvent(fqdn_listname))
mlist = config.db.store.find(
MailingList,
MailingList.list_name == listname,
@@ -74,6 +76,7 @@ class ListManager:
def delete(self, mlist):
"""See `IListManager`."""
fqdn_listname = mlist.fqdn_listname
+ notify(ListDeletingEvent(mlist))
config.db.store.remove(mlist)
notify(ListDeletedEvent(fqdn_listname))
diff --git a/src/mailman/model/tests/test_listmanager.py b/src/mailman/model/tests/test_listmanager.py
index f7caccdb0..8ea36d9b7 100644
--- a/src/mailman/model/tests/test_listmanager.py
+++ b/src/mailman/model/tests/test_listmanager.py
@@ -30,9 +30,16 @@ import unittest
from zope.component import getUtility
from mailman.app.lifecycle import create_list
+from mailman.app.moderator import hold_message
from mailman.interfaces.listmanager import (
- IListManager, ListCreatedEvent, ListDeletedEvent)
-from mailman.testing.helpers import event_subscribers
+ IListManager, ListCreatedEvent, ListCreatingEvent, ListDeletedEvent,
+ ListDeletingEvent)
+from mailman.interfaces.messages import IMessageStore
+from mailman.interfaces.requests import IRequests
+from mailman.interfaces.subscriptions import ISubscriptionService
+from mailman.interfaces.usermanager import IUserManager
+from mailman.testing.helpers import (
+ event_subscribers, specialized_message_from_string)
from mailman.testing.layers import ConfigLayer
@@ -41,18 +48,21 @@ class TestListManager(unittest.TestCase):
layer = ConfigLayer
def setUp(self):
- self._event = None
+ self._events = []
def _record_event(self, event):
- self._event = event
+ self._events.append(event)
def test_create_list_event(self):
# Test that creating a list in the list manager propagates the
- # expected event.
+ # expected events.
with event_subscribers(self._record_event):
mlist = getUtility(IListManager).create('test@example.com')
- self.assertTrue(isinstance(self._event, ListCreatedEvent))
- self.assertEqual(self._event.mailing_list, mlist)
+ self.assertEqual(len(self._events), 2)
+ self.assertTrue(isinstance(self._events[0], ListCreatingEvent))
+ self.assertEqual(self._events[0].fqdn_listname, 'test@example.com')
+ self.assertTrue(isinstance(self._events[1], ListCreatedEvent))
+ self.assertEqual(self._events[1].mailing_list, mlist)
def test_delete_list_event(self):
# Test that deleting a list in the list manager propagates the
@@ -60,12 +70,67 @@ class TestListManager(unittest.TestCase):
mlist = create_list('another@example.com')
with event_subscribers(self._record_event):
getUtility(IListManager).delete(mlist)
- self.assertTrue(isinstance(self._event, ListDeletedEvent))
- self.assertEqual(self._event.fqdn_listname, 'another@example.com')
+ self.assertEqual(len(self._events), 2)
+ self.assertTrue(isinstance(self._events[0], ListDeletingEvent))
+ self.assertEqual(self._events[0].mailing_list, mlist)
+ self.assertTrue(isinstance(self._events[1], ListDeletedEvent))
+ self.assertEqual(self._events[1].fqdn_listname, 'another@example.com')
+
+
+
+class TestListLifecycleEvents(unittest.TestCase):
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._ant = create_list('ant@example.com')
+ self._bee = create_list('bee@example.com')
+ self._usermanager = getUtility(IUserManager)
+
+ def test_members_are_deleted_when_mailing_list_is_deleted(self):
+ # When a mailing list with members is deleted, all the Member records
+ # are also deleted.
+ anne = self._usermanager.create_address('anne@example.com')
+ bart = self._usermanager.create_address('bart@example.com')
+ anne_ant = self._ant.subscribe(anne)
+ anne_bee = self._bee.subscribe(anne)
+ bart_ant = self._ant.subscribe(bart)
+ anne_ant_id = anne_ant.member_id
+ anne_bee_id = anne_bee.member_id
+ bart_ant_id = bart_ant.member_id
+ getUtility(IListManager).delete(self._ant)
+ service = getUtility(ISubscriptionService)
+ # We deleted the ant@example.com mailing list. Anne's and Bart's
+ # membership in this list should now be removed, but Anne's membership
+ # in bee@example.com should still exist.
+ self.assertEqual(service.get_member(anne_ant_id), None)
+ self.assertEqual(service.get_member(bart_ant_id), None)
+ self.assertEqual(service.get_member(anne_bee_id), anne_bee)
+
+ def test_requests_are_deleted_when_mailing_list_is_deleted(self):
+ # When a mailing list is deleted, its requests database is deleted
+ # too, e.g. all its message hold requests (but not the messages
+ # themselves).
+ msg = specialized_message_from_string("""\
+From: anne@example.com
+To: ant@example.com
+Subject: Hold me
+Message-ID: <argon>
+
+""")
+ request_id = hold_message(self._ant, msg)
+ getUtility(IListManager).delete(self._ant)
+ # This is a hack. ListRequests don't access self._mailinglist in
+ # their get_request() method.
+ requestsdb = getUtility(IRequests).get_list_requests(None)
+ request = requestsdb.get_request(request_id)
+ self.assertEqual(request, None)
+ saved_message = getUtility(IMessageStore).get_message_by_id('<argon>')
+ self.assertEqual(saved_message.as_string(), msg.as_string())
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestListManager))
+ suite.addTest(unittest.makeSuite(TestListLifecycleEvents))
return suite
diff --git a/src/mailman/model/tests/test_member.py b/src/mailman/model/tests/test_member.py
index 0fc18cfa6..7906d8983 100644
--- a/src/mailman/model/tests/test_member.py
+++ b/src/mailman/model/tests/test_member.py
@@ -28,9 +28,7 @@ __all__ = [
import unittest
from mailman.app.lifecycle import create_list
-from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.member import MembershipError
-from mailman.interfaces.subscriptions import ISubscriptionService
from mailman.interfaces.user import UnverifiedAddressError
from mailman.interfaces.usermanager import IUserManager
from mailman.testing.layers import ConfigLayer
@@ -100,38 +98,7 @@ class TestMember(unittest.TestCase):
-class TestMembership(unittest.TestCase):
- layer = ConfigLayer
-
- def setUp(self):
- self._ant = create_list('ant@example.com')
- self._bee = create_list('bee@example.com')
- self._usermanager = getUtility(IUserManager)
-
- def test_members_are_deleted_when_mailing_list_is_deleted(self):
- # When a mailing list with members is deleted, all the Member records
- # are also deleted.
- anne = self._usermanager.create_address('anne@example.com')
- bart = self._usermanager.create_address('bart@example.com')
- anne_ant = self._ant.subscribe(anne)
- anne_bee = self._bee.subscribe(anne)
- bart_ant = self._ant.subscribe(bart)
- anne_ant_id = anne_ant.member_id
- anne_bee_id = anne_bee.member_id
- bart_ant_id = bart_ant.member_id
- getUtility(IListManager).delete(self._ant)
- service = getUtility(ISubscriptionService)
- # We deleted the ant@example.com mailing list. Anne's and Bart's
- # membership in this list should now be removed, but Anne's membership
- # in bee@example.com should still exist.
- self.assertEqual(service.get_member(anne_ant_id), None)
- self.assertEqual(service.get_member(bart_ant_id), None)
- self.assertEqual(service.get_member(anne_bee_id), anne_bee)
-
-
-
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestMember))
- suite.addTest(unittest.makeSuite(TestMembership))
return suite
diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py
index 1a168dd0c..144ae1ffb 100644
--- a/src/mailman/testing/helpers.py
+++ b/src/mailman/testing/helpers.py
@@ -29,6 +29,7 @@ __all__ = [
'get_queue_messages',
'make_testable_runner',
'reset_the_world',
+ 'specialized_message_from_string',
'subscribe',
'wait_for_webservice',
]