diff options
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 15 | ||||
| -rw-r--r-- | src/mailman/interfaces/member.py | 31 | ||||
| -rw-r--r-- | src/mailman/model/docs/membership.rst | 23 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 5 | ||||
| -rw-r--r-- | src/mailman/model/member.py | 6 |
5 files changed, 72 insertions, 8 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index 64df34ef1..b9720b960 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -73,18 +73,21 @@ Interfaces `IMailingList` to an `IBanManager` to manage the bans for a specific mailing list. To manage the global bans, adapt ``None``. -Integration ------------ - * Added support for Postfix `relay_domains` setting for better virtual domain - support. Contributed by Jimmy Bergman. - Commands -------- * `bin/mailman aliases` loses the `--output`, `--format`, and `--simple` arguments, and adds a `--directory` argument. This is necessary to support the Postfix `relay_domains` support. * `bin/mailman start` was passing the wrong relative path to its runner - subprocesses when -C was given. LP: #982551 + subprocesses when -C was given. (LP: #982551) + +Other +----- + * Added support for Postfix `relay_domains` setting for better virtual domain + support. Contributed by Jimmy Bergman. + * Two new events are triggered on membership changes: `SubscriptionEvent` + when a new member joins a mailing list, and an `UnsubscriptionEvent` when a + member leaves a mailing list. (LP: #1047286) Bugs ---- diff --git a/src/mailman/interfaces/member.py b/src/mailman/interfaces/member.py index 997338835..815bda2d4 100644 --- a/src/mailman/interfaces/member.py +++ b/src/mailman/interfaces/member.py @@ -26,10 +26,13 @@ __all__ = [ 'DeliveryStatus', 'IMember', 'MemberRole', + 'MembershipChangeEvent', 'MembershipError', 'MembershipIsBannedError', 'MissingPreferredAddressError', 'NotAMemberError', + 'SubscriptionEvent', + 'UnsubscriptionEvent', ] @@ -74,6 +77,34 @@ class MemberRole(Enum): +class MembershipChangeEvent: + """Base class for subscription/unsubscription events.""" + + def __init__(self, mlist, member): + self.mlist = mlist + self.member = member + + +class SubscriptionEvent(MembershipChangeEvent): + """Event which gets triggered when a user joins a mailing list.""" + + def __str__(self): + return '{0} joined {1}'.format(self.member.address, self.mlist.list_id) + + +class UnsubscriptionEvent(MembershipChangeEvent): + """Event which gets triggered when a user leaves a mailing list. + + One thing to keep in mind: because the IMember is deleted when the + unsubscription happens, this event actually gets triggered just before the + member is unsubscribed. + """ + + def __str__(self): + return '{0} left {1}'.format(self.member.address, self.mlist.list_id) + + + class MembershipError(MailmanError): """Base exception for all membership errors.""" diff --git a/src/mailman/model/docs/membership.rst b/src/mailman/model/docs/membership.rst index 3286bfe6e..f257f25ce 100644 --- a/src/mailman/model/docs/membership.rst +++ b/src/mailman/model/docs/membership.rst @@ -315,3 +315,26 @@ Now her membership reflects the new address. >>> for m in bee.members.members: ... print m.member_id.int, m.mailing_list.list_id, m.address.email 7 bee.example.com gperson@example.com + + +Events +====== + +An event is triggered when a new member is subscribed to a mailing list. +:: + + >>> from mailman.testing.helpers import event_subscribers + >>> def handle_event(event): + ... print event + + >>> cat = create_list('cat@example.com') + >>> herb = user_manager.create_address('herb@example.com') + >>> with event_subscribers(handle_event): + ... member = cat.subscribe(herb) + herb@example.com joined cat.example.com + +An event is triggered when a member is unsubscribed from a mailing list. + + >>> with event_subscribers(handle_event): + ... member.unsubscribe() + herb@example.com left cat.example.com diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 2c55540be..324e1a1c8 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -33,6 +33,7 @@ from storm.locals import ( TimeDelta, Unicode) from urlparse import urljoin from zope.component import getUtility +from zope.event import notify from zope.interface import implementer from mailman.config import config @@ -50,7 +51,8 @@ from mailman.interfaces.mailinglist import ( IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization, ReplyToMunging) from mailman.interfaces.member import ( - AlreadySubscribedError, MemberRole, MissingPreferredAddressError) + AlreadySubscribedError, MemberRole, MissingPreferredAddressError, + SubscriptionEvent) from mailman.interfaces.mime import FilterType from mailman.interfaces.nntp import NewsgroupModeration from mailman.interfaces.user import IUser @@ -493,6 +495,7 @@ class MailingList(Model): subscriber=subscriber) member.preferences = Preferences() store.add(member) + notify(SubscriptionEvent(self, member)) return member diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py index 76fe2f992..c189983b9 100644 --- a/src/mailman/model/member.py +++ b/src/mailman/model/member.py @@ -27,6 +27,7 @@ __all__ = [ from storm.locals import Int, Reference, Unicode from storm.properties import UUID from zope.component import getUtility +from zope.event import notify from zope.interface import implementer from mailman.core.constants import system_preferences @@ -36,7 +37,8 @@ from mailman.database.types import Enum from mailman.interfaces.action import Action from mailman.interfaces.address import IAddress from mailman.interfaces.listmanager import IListManager -from mailman.interfaces.member import IMember, MemberRole, MembershipError +from mailman.interfaces.member import ( + IMember, MemberRole, MembershipError, UnsubscriptionEvent) from mailman.interfaces.user import IUser, UnverifiedAddressError from mailman.interfaces.usermanager import IUserManager from mailman.utilities.uid import UniqueIDFactory @@ -186,5 +188,7 @@ class Member(Model): @dbconnection def unsubscribe(self, store): """See `IMember`.""" + # Yes, this must get triggered before self is deleted. + notify(UnsubscriptionEvent(self.mailing_list, self)) store.remove(self.preferences) store.remove(self) |
