diff options
| author | Barry Warsaw | 2014-04-14 12:14:13 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2014-04-14 12:14:13 -0400 |
| commit | 403cbf23c07839b60c85c0bc791b6437f05c8a85 (patch) | |
| tree | b36d0ecab20e01f23bcf66ab2b27633aaf3e99c3 /src/mailman/app | |
| parent | ff6df86000da8fcb055101c5cede36b27cb0480a (diff) | |
| parent | 3a9725b91ef822122a70170333d71b58e1788a78 (diff) | |
| download | mailman-403cbf23c07839b60c85c0bc791b6437f05c8a85.tar.gz mailman-403cbf23c07839b60c85c0bc791b6437f05c8a85.tar.zst mailman-403cbf23c07839b60c85c0bc791b6437f05c8a85.zip | |
Trunk merge
Diffstat (limited to 'src/mailman/app')
| -rw-r--r-- | src/mailman/app/bounces.py | 4 | ||||
| -rw-r--r-- | src/mailman/app/commands.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/domain.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/events.py | 13 | ||||
| -rw-r--r-- | src/mailman/app/inject.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/lifecycle.py | 29 | ||||
| -rw-r--r-- | src/mailman/app/membership.py | 26 | ||||
| -rw-r--r-- | src/mailman/app/moderator.py | 7 | ||||
| -rw-r--r-- | src/mailman/app/notifications.py | 34 | ||||
| -rw-r--r-- | src/mailman/app/registrar.py | 79 | ||||
| -rw-r--r-- | src/mailman/app/replybot.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/subscriptions.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/templates.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_bounces.py | 5 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_inject.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_lifecycle.py | 16 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_membership.py | 43 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_moderation.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_notifications.py | 44 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_registration.py | 132 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_subscriptions.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_templates.py | 2 |
22 files changed, 324 insertions, 128 deletions
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py index 0cc03d9c0..101d96f2a 100644 --- a/src/mailman/app/bounces.py +++ b/src/mailman/app/bounces.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -196,7 +196,7 @@ def send_probe(member, msg): member.mailing_list.list_id) text = make('probe.txt', mlist, member.preferred_language.code, listname=mlist.fqdn_listname, - address= member.address.email, + address=member.address.email, optionsurl=member.options_url, owneraddr=mlist.owner_address, ) diff --git a/src/mailman/app/commands.py b/src/mailman/app/commands.py index 7cde4e923..8dbca8d4b 100644 --- a/src/mailman/app/commands.py +++ b/src/mailman/app/commands.py @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2008-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/domain.py b/src/mailman/app/domain.py index c8fad4d33..ecaa3c230 100644 --- a/src/mailman/app/domain.py +++ b/src/mailman/app/domain.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py index a81ded655..3730d5aad 100644 --- a/src/mailman/app/events.py +++ b/src/mailman/app/events.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -27,7 +27,8 @@ __all__ = [ from zope import event -from mailman.app import domain, moderator, subscriptions +from mailman.app import ( + domain, membership, moderator, registrar, subscriptions) from mailman.core import i18n, switchboard from mailman.languages import manager as language_manager from mailman.styles import manager as style_manager @@ -39,11 +40,13 @@ def initialize(): """Initialize global event subscribers.""" event.subscribers.extend([ domain.handle_DomainDeletingEvent, + i18n.handle_ConfigurationUpdatedEvent, + language_manager.handle_ConfigurationUpdatedEvent, + membership.handle_SubscriptionEvent, moderator.handle_ListDeletingEvent, passwords.handle_ConfigurationUpdatedEvent, + registrar.handle_ConfirmationNeededEvent, + style_manager.handle_ConfigurationUpdatedEvent, subscriptions.handle_ListDeletingEvent, switchboard.handle_ConfigurationUpdatedEvent, - i18n.handle_ConfigurationUpdatedEvent, - style_manager.handle_ConfigurationUpdatedEvent, - language_manager.handle_ConfigurationUpdatedEvent, ]) diff --git a/src/mailman/app/inject.py b/src/mailman/app/inject.py index e9a532252..4c182657d 100644 --- a/src/mailman/app/inject.py +++ b/src/mailman/app/inject.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/lifecycle.py b/src/mailman/app/lifecycle.py index 66e21421e..676953ebe 100644 --- a/src/mailman/app/lifecycle.py +++ b/src/mailman/app/lifecycle.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -27,6 +27,7 @@ __all__ = [ import os +import errno import shutil import logging @@ -98,27 +99,13 @@ def create_list(fqdn_listname, owners=None, style_name=None): def remove_list(mlist): """Remove the list and all associated artifacts and subscriptions.""" fqdn_listname = mlist.fqdn_listname - removeables = [] # Delete the mailing list from the database. getUtility(IListManager).delete(mlist) # Do the MTA-specific list deletion tasks call_name(config.mta.incoming).delete(mlist) - # Remove the list directory. - removeables.append(os.path.join(config.LIST_DATA_DIR, fqdn_listname)) - # Remove any stale locks associated with the list. - for filename in os.listdir(config.LOCK_DIR): - fn_listname, dot, rest = filename.partition('.') - if fn_listname == fqdn_listname: - removeables.append(os.path.join(config.LOCK_DIR, filename)) - # Now that we know what files and directories to delete, delete them. - for target in removeables: - if not os.path.exists(target): - pass - elif os.path.islink(target): - os.unlink(target) - elif os.path.isdir(target): - shutil.rmtree(target) - elif os.path.isfile(target): - os.unlink(target) - else: - log.error('Could not delete list artifact: %s', target) + # Remove the list directory, if it exists. + try: + shutil.rmtree(os.path.join(config.LIST_DATA_DIR, fqdn_listname)) + except OSError as error: + if error.errno != errno.ENOENT: + raise diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py index fc76b00fc..fdeb6e9c4 100644 --- a/src/mailman/app/membership.py +++ b/src/mailman/app/membership.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -17,26 +17,28 @@ """Application support for membership management.""" -from __future__ import absolute_import, unicode_literals +from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'add_member', 'delete_member', + 'handle_SubscriptionEvent', ] from email.utils import formataddr from zope.component import getUtility -from mailman.app.notifications import send_goodbye_message +from mailman.app.notifications import ( + send_goodbye_message, send_welcome_message) from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import OwnerNotification from mailman.interfaces.address import IEmailValidator from mailman.interfaces.bans import IBanManager from mailman.interfaces.member import ( - MemberRole, MembershipIsBannedError, NotAMemberError) + MemberRole, MembershipIsBannedError, NotAMemberError, SubscriptionEvent) from mailman.interfaces.usermanager import IUserManager from mailman.utilities.i18n import make @@ -156,3 +158,19 @@ def delete_member(mlist, email, admin_notif=None, userack=None): msg = OwnerNotification(mlist, subject, text, roster=mlist.administrators) msg.send(mlist) + + + +def handle_SubscriptionEvent(event): + if not isinstance(event, SubscriptionEvent): + return + # Only send a notification message if the mailing list is configured to do + # so, and the member being added is a list member (as opposed to a + # moderator, non-member, or owner). + member = event.member + if member.role is not MemberRole.member: + return + mlist = member.mailing_list + if not mlist.send_welcome_message: + return + send_welcome_message(mlist, member, member.preferred_language) diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py index 59fcb0976..046450305 100644 --- a/src/mailman/app/moderator.py +++ b/src/mailman/app/moderator.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -38,8 +38,7 @@ from email.utils import formataddr, formatdate, getaddresses, make_msgid from zope.component import getUtility from mailman.app.membership import add_member, delete_member -from mailman.app.notifications import ( - send_admin_subscription_notice, send_welcome_message) +from mailman.app.notifications import send_admin_subscription_notice from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import UserNotification @@ -259,8 +258,6 @@ def handle_subscription(mlist, id, action, comment=None): # request was made and accepted. pass else: - if mlist.send_welcome_message: - send_welcome_message(mlist, address, language, delivery_mode) if mlist.admin_notify_mchanges: send_admin_subscription_notice( mlist, address, display_name, language) diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py index 8cbdce450..1fa1fe01e 100644 --- a/src/mailman/app/notifications.py +++ b/src/mailman/app/notifications.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -65,44 +65,36 @@ def _get_message(uri_template, mlist, language): -def send_welcome_message(mlist, address, language, delivery_mode, text=''): +def send_welcome_message(mlist, member, language, text=''): """Send a welcome message to a subscriber. Prepending to the standard welcome message template is the mailing list's welcome message, if there is one. - :param mlist: the mailing list + :param mlist: The mailing list. :type mlist: IMailingList - :param address: The address to respond to - :type address: string - :param language: the language of the response + :param member: The member to send the welcome message to. + :param address: IMember + :param language: The language of the response. :type language: ILanguage - :param delivery_mode: the type of delivery the subscriber is getting - :type delivery_mode: DeliveryMode """ - welcome_message = _get_message(mlist.welcome_message_uri, - mlist, language) - # Find the IMember object which is subscribed to the mailing list, because - # from there, we can get the member's options url. - member = mlist.members.get_member(address) - user_name = member.user.display_name + welcome_message = _get_message(mlist.welcome_message_uri, mlist, language) options_url = member.options_url # Get the text from the template. + display_name = ('' if member.user is None else member.user.display_name) text = expand(welcome_message, dict( fqdn_listname=mlist.fqdn_listname, list_name=mlist.display_name, listinfo_uri=mlist.script_url('listinfo'), list_requests=mlist.request_address, - user_name=user_name, - user_address=address, + user_name=display_name, + user_address=member.address.email, user_options_uri=options_url, )) - if delivery_mode is not DeliveryMode.regular: - digmode = _(' (Digest mode)') - else: - digmode = '' + digmode = ('' if member.delivery_mode is DeliveryMode.regular + else _(' (Digest mode)')) msg = UserNotification( - formataddr((user_name, address)), + formataddr((display_name, member.address.email)), mlist.request_address, _('Welcome to the "$mlist.display_name" mailing list${digmode}'), text, language) diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py index 0f3fbee59..aa4e35483 100644 --- a/src/mailman/app/registrar.py +++ b/src/mailman/app/registrar.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -22,22 +22,23 @@ from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'Registrar', + 'handle_ConfirmationNeededEvent', ] import logging from zope.component import getUtility +from zope.event import notify from zope.interface import implementer -from mailman.app.notifications import send_welcome_message from mailman.core.i18n import _ from mailman.email.message import UserNotification from mailman.interfaces.address import IEmailValidator from mailman.interfaces.listmanager import IListManager from mailman.interfaces.member import DeliveryMode, MemberRole from mailman.interfaces.pending import IPendable, IPendings -from mailman.interfaces.registrar import IRegistrar +from mailman.interfaces.registrar import ConfirmationNeededEvent, IRegistrar from mailman.interfaces.templates import ITemplateLoader from mailman.interfaces.usermanager import IUserManager from mailman.utilities.datetime import now @@ -69,29 +70,13 @@ class Registrar: type=PendableRegistration.PEND_KEY, email=email, display_name=display_name, - delivery_mode=delivery_mode.name) - pendable['list_name'] = mlist.fqdn_listname + delivery_mode=delivery_mode.name, + list_id=mlist.list_id) token = getUtility(IPendings).add(pendable) - # There are three ways for a user to confirm their subscription. They - # can reply to the original message and let the VERP'd return address - # encode the token, they can reply to the robot and keep the token in - # the Subject header, or they can click on the URL in the body of the - # message and confirm through the web. - subject = 'confirm ' + token - confirm_address = mlist.confirm_address(token) - # For i18n interpolation. - confirm_url = mlist.domain.confirm_url(token) - email_address = email - domain_name = mlist.domain.mail_host - contact_address = mlist.domain.contact_address - # Send a verification email to the address. - template = getUtility(ITemplateLoader).get( - 'mailman:///{0}/{1}/confirm.txt'.format( - mlist.fqdn_listname, - mlist.preferred_language.code)) - text = _(template) - msg = UserNotification(email, confirm_address, subject, text) - msg.send(mlist) + # We now have everything we need to begin the confirmation dance. + # Trigger the event to start the ball rolling, and return the + # generated token. + notify(ConfirmationNeededEvent(mlist, pendable, token)) return token def confirm(self, token): @@ -103,7 +88,6 @@ class Registrar: missing = object() email = pendable.get('email', missing) display_name = pendable.get('display_name', missing) - list_name = pendable.get('list_name', missing) pended_delivery_mode = pendable.get('delivery_mode', 'regular') try: delivery_mode = DeliveryMode[pended_delivery_mode] @@ -151,20 +135,43 @@ class Registrar: pass address.verified_on = now() # If this registration is tied to a mailing list, subscribe the person - # to the list right now, and possibly send a welcome message. - list_name = pendable.get('list_name') - if list_name is not None: - mlist = getUtility(IListManager).get(list_name) - if mlist: + # to the list right now. That will generate a SubscriptionEvent, + # which can be used to send a welcome message. + list_id = pendable.get('list_id') + if list_id is not None: + mlist = getUtility(IListManager).get_by_list_id(list_id) + if mlist is not None: member = mlist.subscribe(address, MemberRole.member) member.preferences.delivery_mode = delivery_mode - if mlist.send_welcome_message: - send_welcome_message(mlist, - address.email, - mlist.preferred_language, - delivery_mode) return True def discard(self, token): # Throw the record away. getUtility(IPendings).confirm(token) + + + +def handle_ConfirmationNeededEvent(event): + if not isinstance(event, ConfirmationNeededEvent): + return + # There are three ways for a user to confirm their subscription. They + # can reply to the original message and let the VERP'd return address + # encode the token, they can reply to the robot and keep the token in + # the Subject header, or they can click on the URL in the body of the + # message and confirm through the web. + subject = 'confirm ' + event.token + mlist = getUtility(IListManager).get_by_list_id(event.pendable['list_id']) + confirm_address = mlist.confirm_address(event.token) + # For i18n interpolation. + confirm_url = mlist.domain.confirm_url(event.token) + email_address = event.pendable['email'] + domain_name = mlist.domain.mail_host + contact_address = mlist.domain.contact_address + # Send a verification email to the address. + template = getUtility(ITemplateLoader).get( + 'mailman:///{0}/{1}/confirm.txt'.format( + mlist.fqdn_listname, + mlist.preferred_language.code)) + text = _(template) + msg = UserNotification(email_address, confirm_address, subject, text) + msg.send(mlist) diff --git a/src/mailman/app/replybot.py b/src/mailman/app/replybot.py index 619b9718e..30d547d8a 100644 --- a/src/mailman/app/replybot.py +++ b/src/mailman/app/replybot.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py index 0995202b6..d80069ba5 100644 --- a/src/mailman/app/subscriptions.py +++ b/src/mailman/app/subscriptions.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2009-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/templates.py b/src/mailman/app/templates.py index f0b4222cb..742584b49 100644 --- a/src/mailman/app/templates.py +++ b/src/mailman/app/templates.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2012-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/tests/test_bounces.py b/src/mailman/app/tests/test_bounces.py index f6d5669a4..5eb518786 100644 --- a/src/mailman/app/tests/test_bounces.py +++ b/src/mailman/app/tests/test_bounces.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -198,6 +198,7 @@ class TestSendProbe(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False self._member = add_member(self._mlist, 'anne@example.com', 'Anne Person', 'xxx', DeliveryMode.regular, 'en') @@ -355,6 +356,7 @@ class TestProbe(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False self._member = add_member(self._mlist, 'anne@example.com', 'Anne Person', 'xxx', DeliveryMode.regular, 'en') @@ -395,6 +397,7 @@ class TestMaybeForward(unittest.TestCase): site_owner: postmaster@example.com """) self._mlist = create_list('test@example.com') + self._mlist.send_welcome_message = False self._msg = mfs("""\ From: bouncer@example.com To: test-bounces@example.com diff --git a/src/mailman/app/tests/test_inject.py b/src/mailman/app/tests/test_inject.py index 78204aae3..f7f750662 100644 --- a/src/mailman/app/tests/test_inject.py +++ b/src/mailman/app/tests/test_inject.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/tests/test_lifecycle.py b/src/mailman/app/tests/test_lifecycle.py index cea06359d..0fb54f193 100644 --- a/src/mailman/app/tests/test_lifecycle.py +++ b/src/mailman/app/tests/test_lifecycle.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2012-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -25,11 +25,14 @@ __all__ = [ ] +import os +import shutil import unittest +from mailman.config import config from mailman.interfaces.address import InvalidEmailAddressError from mailman.interfaces.domain import BadDomainSpecificationError -from mailman.app.lifecycle import create_list +from mailman.app.lifecycle import create_list, remove_list from mailman.testing.layers import ConfigLayer @@ -48,3 +51,12 @@ class TestLifecycle(unittest.TestCase): # Creating a list with an unregistered domain raises an exception. self.assertRaises(BadDomainSpecificationError, create_list, 'test@nodomain.example.org') + + def test_remove_list_error(self): + # An error occurs while deleting the list's data directory. + mlist = create_list('test@example.com') + data_dir = os.path.join(config.LIST_DATA_DIR, mlist.fqdn_listname) + os.chmod(data_dir, 0) + self.addCleanup(shutil.rmtree, data_dir) + self.assertRaises(OSError, remove_list, mlist) + os.chmod(data_dir, 0o777) diff --git a/src/mailman/app/tests/test_membership.py b/src/mailman/app/tests/test_membership.py index 07994f34d..95e8de1d0 100644 --- a/src/mailman/app/tests/test_membership.py +++ b/src/mailman/app/tests/test_membership.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -17,10 +17,13 @@ """Tests of application level membership functions.""" -from __future__ import absolute_import, unicode_literals +from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ + 'TestAddMember', + 'TestAddMemberPassword', + 'TestDeleteMember', ] @@ -29,17 +32,18 @@ import unittest from zope.component import getUtility from mailman.app.lifecycle import create_list -from mailman.app.membership import add_member +from mailman.app.membership import add_member, delete_member from mailman.core.constants import system_preferences from mailman.interfaces.bans import IBanManager from mailman.interfaces.member import ( - AlreadySubscribedError, DeliveryMode, MemberRole, MembershipIsBannedError) + AlreadySubscribedError, DeliveryMode, MemberRole, MembershipIsBannedError, + NotAMemberError) from mailman.interfaces.usermanager import IUserManager from mailman.testing.layers import ConfigLayer -class AddMemberTest(unittest.TestCase): +class TestAddMember(unittest.TestCase): layer = ConfigLayer def setUp(self): @@ -70,10 +74,13 @@ class AddMemberTest(unittest.TestCase): # Test that members who are banned by specific address cannot # subscribe to the mailing list. IBanManager(self._mlist).ban('anne@example.com') - self.assertRaises( - MembershipIsBannedError, - add_member, self._mlist, 'anne@example.com', 'Anne Person', - '123', DeliveryMode.regular, system_preferences.preferred_language) + with self.assertRaises(MembershipIsBannedError) as cm: + add_member(self._mlist, 'anne@example.com', 'Anne Person', + '123', DeliveryMode.regular, + system_preferences.preferred_language) + self.assertEqual( + str(cm.exception), + 'anne@example.com is not allowed to subscribe to test@example.com') def test_add_member_globally_banned(self): # Test that members who are banned by specific address cannot @@ -165,7 +172,7 @@ class AddMemberTest(unittest.TestCase): -class AddMemberPasswordTest(unittest.TestCase): +class TestAddMemberPassword(unittest.TestCase): layer = ConfigLayer def setUp(self): @@ -177,3 +184,19 @@ class AddMemberPasswordTest(unittest.TestCase): 'Anne Person', 'abc', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.user.password, '{plaintext}abc') + + + +class TestDeleteMember(unittest.TestCase): + layer = ConfigLayer + + def setUp(self): + self._mlist = create_list('test@example.com') + + def test_delete_member_not_a_member(self): + # Try to delete an address which is not a member of the mailing list. + with self.assertRaises(NotAMemberError) as cm: + delete_member(self._mlist, 'noperson@example.com') + self.assertEqual( + str(cm.exception), + 'noperson@example.com is not a member of test@example.com') diff --git a/src/mailman/app/tests/test_moderation.py b/src/mailman/app/tests/test_moderation.py index 529116d35..edb6b8c28 100644 --- a/src/mailman/app/tests/test_moderation.py +++ b/src/mailman/app/tests/test_moderation.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/tests/test_notifications.py b/src/mailman/app/tests/test_notifications.py index e49228d0a..4cdc1c01c 100644 --- a/src/mailman/app/tests/test_notifications.py +++ b/src/mailman/app/tests/test_notifications.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2012-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # @@ -33,10 +33,9 @@ from zope.component import getUtility from mailman.app.lifecycle import create_list from mailman.app.membership import add_member -from mailman.app.notifications import send_welcome_message from mailman.config import config from mailman.interfaces.languages import ILanguageManager -from mailman.interfaces.member import DeliveryMode +from mailman.interfaces.member import DeliveryMode, MemberRole from mailman.testing.helpers import get_queue_messages from mailman.testing.layers import ConfigLayer @@ -82,11 +81,8 @@ Welcome to the $list_name mailing list. shutil.rmtree(self.var_dir) def test_welcome_message(self): - en = getUtility(ILanguageManager).get('en') add_member(self._mlist, 'anne@example.com', 'Anne Person', 'password', DeliveryMode.regular, 'en') - send_welcome_message(self._mlist, 'anne@example.com', en, - DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages('virgin') self.assertEqual(len(messages), 1) @@ -110,16 +106,42 @@ Welcome to the Test List mailing list. 'mailman:///$listname/$language/welcome.txt') # Add the xx language and subscribe Anne using it. manager = getUtility(ILanguageManager) - xx = manager.add('xx', 'us-ascii', 'Xlandia') + manager.add('xx', 'us-ascii', 'Xlandia') add_member(self._mlist, 'anne@example.com', 'Anne Person', 'password', DeliveryMode.regular, 'xx') - send_welcome_message(self._mlist, 'anne@example.com', xx, - DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages('virgin') self.assertEqual(len(messages), 1) message = messages[0].msg self.assertEqual(str(message['subject']), 'Welcome to the "Test List" mailing list') - self.assertEqual(message.get_payload(), - 'You just joined the Test List mailing list!') + self.assertMultiLineEqual( + message.get_payload(), + 'You just joined the Test List mailing list!') + + def test_no_welcome_message_to_owners(self): + # Welcome messages go only to mailing list members, not to owners. + add_member(self._mlist, 'anne@example.com', 'Anne Person', + 'password', DeliveryMode.regular, 'xx', + MemberRole.owner) + # There is no welcome message in the virgin queue. + messages = get_queue_messages('virgin') + self.assertEqual(len(messages), 0) + + def test_no_welcome_message_to_nonmembers(self): + # Welcome messages go only to mailing list members, not to nonmembers. + add_member(self._mlist, 'anne@example.com', 'Anne Person', + 'password', DeliveryMode.regular, 'xx', + MemberRole.nonmember) + # There is no welcome message in the virgin queue. + messages = get_queue_messages('virgin') + self.assertEqual(len(messages), 0) + + def test_no_welcome_message_to_moderators(self): + # Welcome messages go only to mailing list members, not to moderators. + add_member(self._mlist, 'anne@example.com', 'Anne Person', + 'password', DeliveryMode.regular, 'xx', + MemberRole.moderator) + # There is no welcome message in the virgin queue. + messages = get_queue_messages('virgin') + self.assertEqual(len(messages), 0) diff --git a/src/mailman/app/tests/test_registration.py b/src/mailman/app/tests/test_registration.py new file mode 100644 index 000000000..ff128ae6f --- /dev/null +++ b/src/mailman/app/tests/test_registration.py @@ -0,0 +1,132 @@ +# Copyright (C) 2012 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 email address registration.""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + 'TestEmailValidation', + 'TestRegistration', + ] + + +import unittest + +from zope.component import getUtility + +from mailman.app.lifecycle import create_list +from mailman.interfaces.address import InvalidEmailAddressError +from mailman.interfaces.pending import IPendings +from mailman.interfaces.registrar import ConfirmationNeededEvent, IRegistrar +from mailman.testing.helpers import event_subscribers +from mailman.testing.layers import ConfigLayer + + + +class TestEmailValidation(unittest.TestCase): + """Test basic email validation.""" + + layer = ConfigLayer + + def setUp(self): + self.registrar = getUtility(IRegistrar) + self.mlist = create_list('alpha@example.com') + + def test_empty_string_is_invalid(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + '') + + def test_no_spaces_allowed(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + 'some name@example.com') + + def test_no_angle_brackets(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + '<script>@example.com') + + def test_ascii_only(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + '\xa0@example.com') + + def test_domain_required(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + 'noatsign') + + def test_full_domain_required(self): + self.assertRaises(InvalidEmailAddressError, + self.registrar.register, self.mlist, + 'nodom@ain') + + + +class TestRegistration(unittest.TestCase): + """Test registration.""" + + layer = ConfigLayer + + def setUp(self): + self.registrar = getUtility(IRegistrar) + self.mlist = create_list('alpha@example.com') + + def test_confirmation_event_received(self): + # Registering an email address generates an event. + def capture_event(event): + self.assertIsInstance(event, ConfirmationNeededEvent) + with event_subscribers(capture_event): + self.registrar.register(self.mlist, 'anne@example.com') + + def test_event_mlist(self): + # The event has a reference to the mailing list being subscribed to. + def capture_event(event): + self.assertIs(event.mlist, self.mlist) + with event_subscribers(capture_event): + self.registrar.register(self.mlist, 'anne@example.com') + + def test_event_pendable(self): + # The event has an IPendable which contains additional information. + def capture_event(event): + pendable = event.pendable + self.assertEqual(pendable['type'], 'registration') + self.assertEqual(pendable['email'], 'anne@example.com') + # The key is present, but the value is None. + self.assertIsNone(pendable['display_name']) + # The default is regular delivery. + self.assertEqual(pendable['delivery_mode'], 'regular') + self.assertEqual(pendable['list_id'], 'alpha.example.com') + with event_subscribers(capture_event): + self.registrar.register(self.mlist, 'anne@example.com') + + def test_token(self): + # Registering the email address returns a token, and this token links + # back to the pendable. + captured_events = [] + def capture_event(event): + captured_events.append(event) + with event_subscribers(capture_event): + token = self.registrar.register(self.mlist, 'anne@example.com') + self.assertEqual(len(captured_events), 1) + event = captured_events[0] + self.assertEqual(event.token, token) + pending = getUtility(IPendings).confirm(token) + self.assertEqual(pending, event.pendable) diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py index 6d269ffac..e5aad18bc 100644 --- a/src/mailman/app/tests/test_subscriptions.py +++ b/src/mailman/app/tests/test_subscriptions.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2011-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # diff --git a/src/mailman/app/tests/test_templates.py b/src/mailman/app/tests/test_templates.py index 59c9a05df..afde68647 100644 --- a/src/mailman/app/tests/test_templates.py +++ b/src/mailman/app/tests/test_templates.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 by the Free Software Foundation, Inc. +# Copyright (C) 2012-2014 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # |
