diff options
| -rw-r--r-- | src/mailman/app/subscriptions.py | 1 | ||||
| -rw-r--r-- | src/mailman/model/docs/registration.rst | 100 | ||||
| -rw-r--r-- | src/mailman/model/docs/subscriptions.rst | 153 |
3 files changed, 149 insertions, 105 deletions
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py index 7dea6c9cf..cfd1b59a7 100644 --- a/src/mailman/app/subscriptions.py +++ b/src/mailman/app/subscriptions.py @@ -615,6 +615,7 @@ class UnsubscriptionManager(BaseSubscriptionManager): pre_confirmed=pre_confirmed, pre_approved=pre_approved) list(workflow) + return workflow.token, workflow.token_owner, workflow.member @public diff --git a/src/mailman/model/docs/registration.rst b/src/mailman/model/docs/registration.rst deleted file mode 100644 index 4b1e13520..000000000 --- a/src/mailman/model/docs/registration.rst +++ /dev/null @@ -1,100 +0,0 @@ -============ -Registration -============ - -When a user wants to join a mailing list, they must register and verify their -email address. Then depending on how the mailing list is configured, they may -need to confirm their subscription and have it approved by the list -moderator. The ``IRegistrar`` interface manages this work flow. - - >>> from mailman.interfaces.registrar import IRegistrar - -Registrars adapt mailing lists. - - >>> from mailman.interfaces.mailinglist import SubscriptionPolicy - >>> mlist = create_list('ant@example.com') - >>> mlist.send_welcome_message = False - >>> mlist.subscription_policy = SubscriptionPolicy.open - >>> registrar = IRegistrar(mlist) - -Usually, addresses are registered, but users with preferred addresses can be -registered too. - - >>> from mailman.interfaces.usermanager import IUserManager - >>> from zope.component import getUtility - >>> anne = getUtility(IUserManager).create_address( - ... 'anne@example.com', 'Anne Person') - - -Register an email address -========================= - -When the registration steps involve confirmation or moderator approval, the -process will pause until these steps are completed. A unique token is created -which represents this work flow. - -Anne attempts to join the mailing list. - - >>> token, token_owner, member = registrar.register(anne) - -Because her email address has not yet been verified, she has not yet become a -member of the mailing list. - - >>> print(member) - None - >>> print(mlist.members.get_member('anne@example.com')) - None - -Once she verifies her email address, she will become a member of the mailing -list. In this case, verifying implies that she also confirms her wish to join -the mailing list. - - >>> token, token_owner, member = registrar.confirm(token) - >>> member - <Member: Anne Person <anne@example.com> on ant@example.com - as MemberRole.member> - >>> mlist.members.get_member('anne@example.com') - <Member: Anne Person <anne@example.com> on ant@example.com - as MemberRole.member> - - -Register a user -=============== - -Users can also register, but they must have a preferred address. The mailing -list will deliver messages to this preferred address. - - >>> bart = getUtility(IUserManager).make_user( - ... 'bart@example.com', 'Bart Person') - -Bart verifies his address and makes it his preferred address. - - >>> from mailman.utilities.datetime import now - >>> preferred = list(bart.addresses)[0] - >>> preferred.verified_on = now() - >>> bart.preferred_address = preferred - -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 - -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 -subscribed to the mailing list. - - >>> token, token_owner, member = registrar.register(bart) - >>> print(member) - None - >>> print(mlist.members.get_member('bart@example.com')) - None - -When the moderator confirms Bart's subscription, he joins the mailing list. - - >>> token, token_owner, member = registrar.confirm(token) - >>> member - <Member: Bart Person <bart@example.com> on ant@example.com - as MemberRole.member> - >>> mlist.members.get_member('bart@example.com') - <Member: Bart Person <bart@example.com> on ant@example.com - as MemberRole.member> diff --git a/src/mailman/model/docs/subscriptions.rst b/src/mailman/model/docs/subscriptions.rst index 14cb36b71..4c079d542 100644 --- a/src/mailman/model/docs/subscriptions.rst +++ b/src/mailman/model/docs/subscriptions.rst @@ -1,14 +1,157 @@ -===================== +=============== + Subscriptions +=============== + +When a user wants to join a mailing list, they must register and verify their +email address. Then depending on how the mailing list is configured, they may +need to confirm their subscription and have it approved by the list moderator. +The ``ISubscriptionManager`` interface manages this work flow. + + >>> from mailman.interfaces.subscriptions import ISubscriptionManager + +To begin, adapt a mailing list to an ``ISubscriptionManager``. This is a +named interface because the same interface manages both subscriptions and +unsubscriptions. + + >>> from zope.component import getAdapter + >>> mlist = create_list('ant@example.com') + >>> manager = getAdapter(mlist, ISubscriptionManager, 'subscribe') + +Either addresses or users with a preferred address can be registered. + + >>> from mailman.interfaces.usermanager import IUserManager + >>> from zope.component import getUtility + >>> anne = getUtility(IUserManager).create_address( + ... 'anne@example.com', 'Anne Person') + + +Subscribing an email address +============================ + +The subscription process requires that the email address be verified. It may +also require confirmation or moderator approval depending on the mailing +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 + +Anne attempts to join the mailing list. A unique token is created which +represents this work flow. + + >>> token, token_owner, member = manager.register(anne) + +Because her email address has not yet been verified, she has not yet become a +member of the mailing list. + + >>> print(member) + None + >>> print(mlist.members.get_member('anne@example.com')) + None + +Once she verifies her email address, she will become a member of the mailing +list. When the subscription policy requires confirmation, the verification +process implies that she also confirms her wish to join the mailing list. + + >>> token, token_owner, member = manager.confirm(token) + >>> member + <Member: Anne Person <anne@example.com> on ant@example.com + as MemberRole.member> + >>> mlist.members.get_member('anne@example.com') + <Member: Anne Person <anne@example.com> on ant@example.com + as MemberRole.member> + + +Subscribing a user +================== + +Users can also register, but they must have a preferred address. The mailing +list will deliver messages to this preferred address. + + >>> bart = getUtility(IUserManager).make_user( + ... 'bart@example.com', 'Bart Person') + +Bart verifies his address and makes it his preferred address. + + >>> from mailman.utilities.datetime import now + >>> preferred = list(bart.addresses)[0] + >>> preferred.verified_on = now() + >>> bart.preferred_address = preferred + +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 + +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 +subscribed to the mailing list. + + >>> token, token_owner, member = manager.register(bart) + >>> print(member) + None + >>> print(mlist.members.get_member('bart@example.com')) + None + +When the moderator confirms Bart's subscription, he joins the mailing list. + + >>> token, token_owner, member = manager.confirm(token) + >>> member + <Member: Bart Person <bart@example.com> on ant@example.com + as MemberRole.member> + >>> mlist.members.get_member('bart@example.com') + <Member: Bart Person <bart@example.com> on ant@example.com + as MemberRole.member> + + +Unsubscribing +============= + +Similarly, unsubscribing a user depends on the mailing list's unsubscription +policy. Of course, since the address or user is already subscribed, implying +that their email address is already verified, that step is not required. To +begin with unsubscribing, you need to adapt the mailing list to the same +interface, but with a different name. + + >>> manager = getAdapter(mlist, ISubscriptionManager, 'unsubscribe') + +If the mailing list's unsubscription policy is open, unregistering the +subscription takes effect immediately. + + >>> mlist.unsubscription_policy = SubscriptionPolicy.open + >>> token, token_owner, member = manager.unregister(anne) + >>> print(mlist.members.get_member('anne@example.com')) + None + +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 + >>> token, token_owner, member = manager.unregister(bart) + +Bart hasn't confirmed yet, so he's still a member of the list. + + >>> mlist.members.get_member('bart@example.com') + <Member: Bart Person <bart@example.com> on ant@example.com + as MemberRole.member> + +Once Bart confirms, he's unsubscribed from the mailing list. + + >>> token, token_owner, member = manager.confirm(token) + >>> print(mlist.members.get_member('bart@example.com')) + None + + Subscription services ===================== The ``ISubscriptionService`` utility provides higher level convenience methods useful for searching, retrieving, iterating, and removing memberships across -all mailing lists on th esystem. Adding new users is handled by the -``IRegistrar`` interface. +all mailing lists on the system. >>> from mailman.interfaces.subscriptions import ISubscriptionService - >>> from zope.component import getUtility >>> service = getUtility(ISubscriptionService) You can use the service to get all members of all mailing lists, for any @@ -30,7 +173,7 @@ When there are some members, of any role on any mailing list, they can be retrieved through the subscription service. >>> from mailman.app.lifecycle import create_list - >>> ant = create_list('ant@example.com') + >>> ant = mlist >>> bee = create_list('bee@example.com') >>> cat = create_list('cat@example.com') |
