diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/app/events.py | 3 | ||||
| -rw-r--r-- | src/mailman/app/moderator.py | 13 | ||||
| -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.py | 16 | ||||
| -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.py | 5 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_listmanager.py | 83 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_member.py | 33 | ||||
| -rw-r--r-- | src/mailman/testing/helpers.py | 1 |
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', ] |
