diff options
| author | Barry Warsaw | 2011-09-02 14:48:48 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2011-09-02 14:48:48 -0400 |
| commit | 340c25de0f8fdd2c4093cf233cd4e999bff52856 (patch) | |
| tree | 995dfe1ea558d7ce9e8431d0b8d47c4e6c6486ac /src | |
| parent | 782f001439572794992e1687dbdacec6f2faa263 (diff) | |
| download | mailman-340c25de0f8fdd2c4093cf233cd4e999bff52856.tar.gz mailman-340c25de0f8fdd2c4093cf233cd4e999bff52856.tar.zst mailman-340c25de0f8fdd2c4093cf233cd4e999bff52856.zip | |
* Four new events are created, and notifications are sent during domain
lifecycle changes:
- DomainCreatingEvent - sent before the domain is created
- DomainCreatedEvent - sent after the domain is created
- DomainDeletingEvent - sent before the domain is deleted
- DomainDeletedEvent - sent after the domain is deleted
* Using the above events, when a domain is deleted, associated mailing lists
are deleted. (LP: #837526)
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/app/domain.py | 42 | ||||
| -rw-r--r-- | src/mailman/app/events.py | 3 | ||||
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 11 | ||||
| -rw-r--r-- | src/mailman/interfaces/domain.py | 32 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 9 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_domain.py | 113 | ||||
| -rw-r--r-- | src/mailman/rest/tests/test_domains.py | 11 |
7 files changed, 216 insertions, 5 deletions
diff --git a/src/mailman/app/domain.py b/src/mailman/app/domain.py new file mode 100644 index 000000000..1674052da --- /dev/null +++ b/src/mailman/app/domain.py @@ -0,0 +1,42 @@ +# Copyright (C) 2011 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""Application level domain support.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'handle_DomainDeletingEvent', + ] + + +from zope.component import getUtility + +from mailman.interfaces.domain import DomainDeletingEvent +from mailman.interfaces.listmanager import IListManager + + + +def handle_DomainDeletingEvent(event): + """Delete all mailing lists in a domain when the domain is deleted.""" + + if not isinstance(event, DomainDeletingEvent): + return + list_manager = getUtility(IListManager) + for mailing_list in event.domain.mailing_lists: + list_manager.delete(mailing_list) diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py index ac318f6b2..2145223f6 100644 --- a/src/mailman/app/events.py +++ b/src/mailman/app/events.py @@ -27,7 +27,7 @@ __all__ = [ from zope import event -from mailman.app import moderator, subscriptions +from mailman.app import domain, moderator, subscriptions @@ -36,4 +36,5 @@ def initialize(): event.subscribers.extend([ moderator.handle_ListDeletingEvent, subscriptions.handle_ListDeletedEvent, + domain.handle_DomainDeletingEvent, ]) diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index 38dc35ab4..2b8a99d28 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -25,9 +25,14 @@ Architecture - ListCreatedEvent - sent after the mailing list is created - ListDeletingEvent - sent before the mailing list is deleted - ListDeletedEvent - sent after the mailing list is deleted - * Using the above events, when a mailing list is deleted, all its members are - deleted, as well as all held message requests (but not the held messages - themselves). (LP: 827036) + * Four new events are created, and notifications are sent during domain + lifecycle changes: + - DomainCreatingEvent - sent before the domain is created + - DomainCreatedEvent - sent after the domain is created + - DomainDeletingEvent - sent before the domain is deleted + - DomainDeletedEvent - sent after the domain is deleted + * Using the above events, when a domain is deleted, associated mailing lists + are deleted. (LP: #837526) * IDomain.email_host -> .mail_host (LP: #831660) * User and Member ids are now proper UUIDs. diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py index e0423f73b..fef32cf96 100644 --- a/src/mailman/interfaces/domain.py +++ b/src/mailman/interfaces/domain.py @@ -22,6 +22,10 @@ from __future__ import absolute_import, unicode_literals __metaclass__ = type __all__ = [ 'BadDomainSpecificationError', + 'DomainCreatedEvent', + 'DomainCreatingEvent', + 'DomainDeletedEvent', + 'DomainDeletingEvent', 'IDomain', 'IDomainManager', ] @@ -41,6 +45,34 @@ class BadDomainSpecificationError(MailmanError): self.domain = domain +class DomainCreatingEvent: + """A domain is about to be created.""" + + def __init__(self, mail_host): + self.mail_host = mail_host + + +class DomainCreatedEvent: + """A domain was created.""" + + def __init__(self, domain): + self.domain = domain + + +class DomainDeletingEvent: + """A domain is about to be deleted.""" + + def __init__(self, domain): + self.domain = domain + + +class DomainDeletedEvent: + """A domain was deleted.""" + + def __init__(self, mail_host): + self.mail_host = mail_host + + class IDomain(Interface): """Interface representing domains.""" diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index c752d4f0b..78918e7a3 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -25,14 +25,17 @@ __all__ = [ 'DomainManager', ] + from urlparse import urljoin, urlparse from storm.locals import Int, Unicode +from zope.event import notify from zope.interface import implements from mailman.config import config from mailman.database.model import Model from mailman.interfaces.domain import ( - BadDomainSpecificationError, IDomain, IDomainManager) + BadDomainSpecificationError, DomainCreatedEvent, DomainCreatingEvent, + DomainDeletedEvent, DomainDeletingEvent, IDomain, IDomainManager) from mailman.model.mailinglist import MailingList @@ -126,13 +129,17 @@ class DomainManager: if self.get(mail_host) is not None: raise BadDomainSpecificationError( 'Duplicate email host: %s' % mail_host) + notify(DomainCreatingEvent(mail_host)) domain = Domain(mail_host, description, base_url, contact_address) config.db.store.add(domain) + notify(DomainCreatedEvent(domain)) return domain def remove(self, mail_host): domain = self[mail_host] + notify(DomainDeletingEvent(domain)) config.db.store.remove(domain) + notify(DomainDeletedEvent(mail_host)) return domain def get(self, mail_host, default=None): diff --git a/src/mailman/model/tests/test_domain.py b/src/mailman/model/tests/test_domain.py new file mode 100644 index 000000000..4ad8a5403 --- /dev/null +++ b/src/mailman/model/tests/test_domain.py @@ -0,0 +1,113 @@ +# Copyright (C) 2011 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""Test domains.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'test_suite', + ] + + +import unittest + +from zope.component import getUtility + +from mailman.app.lifecycle import create_list +from mailman.interfaces.domain import ( + DomainCreatedEvent, DomainCreatingEvent, DomainDeletedEvent, + DomainDeletingEvent, IDomainManager) +from mailman.interfaces.listmanager import IListManager +from mailman.testing.helpers import event_subscribers +from mailman.testing.layers import ConfigLayer + + + +class TestDomainManager(unittest.TestCase): + layer = ConfigLayer + + def setUp(self): + self._events = [] + + def _record_event(self, event): + self._events.append(event) + + def test_create_domain_event(self): + # Test that creating a domain in the domain manager propagates the + # expected events. + with event_subscribers(self._record_event): + domain = getUtility(IDomainManager).add('example.org') + self.assertEqual(len(self._events), 2) + self.assertTrue(isinstance(self._events[0], DomainCreatingEvent)) + self.assertEqual(self._events[0].mail_host, 'example.org') + self.assertTrue(isinstance(self._events[1], DomainCreatedEvent)) + self.assertEqual(self._events[1].domain, domain) + + def test_delete_domain_event(self): + # Test that deleting a domain in the domain manager propagates the + # expected event. + domain = getUtility(IDomainManager).add('example.org') + with event_subscribers(self._record_event): + getUtility(IDomainManager).remove('example.org') + self.assertEqual(len(self._events), 2) + self.assertTrue(isinstance(self._events[0], DomainDeletingEvent)) + self.assertEqual(self._events[0].domain, domain) + self.assertTrue(isinstance(self._events[1], DomainDeletedEvent)) + self.assertEqual(self._events[1].mail_host, 'example.org') + + + +class TestDomainLifecycleEvents(unittest.TestCase): + layer = ConfigLayer + + def setUp(self): + self._domainmanager = getUtility(IDomainManager) + self._org = self._domainmanager.add('example.net') + self._net = self._domainmanager.add('example.org') + + def test_lists_are_deleted_when_domain_is_deleted(self): + # When a domain is deleted, all the mailing lists in that domain are + # also deleted. + create_list('ant@example.net') + create_list('bee@example.net') + cat = create_list('cat@example.org') + dog = create_list('dog@example.org') + ewe = create_list('ewe@example.com') + fly = create_list('fly@example.com') + listmanager = getUtility(IListManager) + self._domainmanager.remove('example.net') + self.assertEqual(listmanager.get('ant@example.net'), None) + self.assertEqual(listmanager.get('bee@example.net'), None) + self.assertEqual(listmanager.get('cat@example.org'), cat) + self.assertEqual(listmanager.get('dog@example.org'), dog) + self.assertEqual(listmanager.get('ewe@example.com'), ewe) + self.assertEqual(listmanager.get('fly@example.com'), fly) + self._domainmanager.remove('example.org') + self.assertEqual(listmanager.get('cat@example.org'), None) + self.assertEqual(listmanager.get('dog@example.org'), None) + self.assertEqual(listmanager.get('ewe@example.com'), ewe) + self.assertEqual(listmanager.get('fly@example.com'), fly) + + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestDomainManager)) + suite.addTest(unittest.makeSuite(TestDomainLifecycleEvents)) + return suite diff --git a/src/mailman/rest/tests/test_domains.py b/src/mailman/rest/tests/test_domains.py index e12d340ae..b04090b14 100644 --- a/src/mailman/rest/tests/test_domains.py +++ b/src/mailman/rest/tests/test_domains.py @@ -28,9 +28,11 @@ __all__ = [ import unittest from urllib2 import HTTPError +from zope.component import getUtility from mailman.app.lifecycle import create_list from mailman.config import config +from mailman.interfaces.listmanager import IListManager from mailman.testing.helpers import call_api from mailman.testing.layers import RESTLayer @@ -64,6 +66,15 @@ class TestDomains(unittest.TestCase): else: raise AssertionError('Expected HTTPError') + def test_lists_are_deleted_when_domain_is_deleted(self): + # /domains/<domain> DELETE removes all associated mailing lists. + create_list('ant@example.com') + config.db.commit() + content, response = call_api( + 'http://localhost:9001/3.0/domains/example.com', method='DELETE') + self.assertEqual(response.status, 204) + self.assertEqual(getUtility(IListManager).get('ant@example.com'), None) + def test_suite(): |
