summaryrefslogtreecommitdiff
path: root/src/mailman/app
diff options
context:
space:
mode:
authorBarry Warsaw2014-04-14 12:14:13 -0400
committerBarry Warsaw2014-04-14 12:14:13 -0400
commit403cbf23c07839b60c85c0bc791b6437f05c8a85 (patch)
treeb36d0ecab20e01f23bcf66ab2b27633aaf3e99c3 /src/mailman/app
parentff6df86000da8fcb055101c5cede36b27cb0480a (diff)
parent3a9725b91ef822122a70170333d71b58e1788a78 (diff)
downloadmailman-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.py4
-rw-r--r--src/mailman/app/commands.py2
-rw-r--r--src/mailman/app/domain.py2
-rw-r--r--src/mailman/app/events.py13
-rw-r--r--src/mailman/app/inject.py2
-rw-r--r--src/mailman/app/lifecycle.py29
-rw-r--r--src/mailman/app/membership.py26
-rw-r--r--src/mailman/app/moderator.py7
-rw-r--r--src/mailman/app/notifications.py34
-rw-r--r--src/mailman/app/registrar.py79
-rw-r--r--src/mailman/app/replybot.py2
-rw-r--r--src/mailman/app/subscriptions.py2
-rw-r--r--src/mailman/app/templates.py2
-rw-r--r--src/mailman/app/tests/test_bounces.py5
-rw-r--r--src/mailman/app/tests/test_inject.py2
-rw-r--r--src/mailman/app/tests/test_lifecycle.py16
-rw-r--r--src/mailman/app/tests/test_membership.py43
-rw-r--r--src/mailman/app/tests/test_moderation.py2
-rw-r--r--src/mailman/app/tests/test_notifications.py44
-rw-r--r--src/mailman/app/tests/test_registration.py132
-rw-r--r--src/mailman/app/tests/test_subscriptions.py2
-rw-r--r--src/mailman/app/tests/test_templates.py2
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.
#