summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/notifications.py41
-rw-r--r--src/mailman/app/templates.py2
-rw-r--r--src/mailman/app/tests/test_notifications.py101
-rw-r--r--src/mailman/model/docs/requests.rst1
-rw-r--r--src/mailman/rest/docs/configuration.rst4
-rw-r--r--src/mailman/templates/en/welcome.txt (renamed from src/mailman/templates/en/subscribeack.txt)12
-rw-r--r--src/mailman/utilities/i18n.py40
-rw-r--r--src/mailman/utilities/string.py2
8 files changed, 160 insertions, 43 deletions
diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py
index 78801402b..3c31fbd23 100644
--- a/src/mailman/app/notifications.py
+++ b/src/mailman/app/notifications.py
@@ -27,15 +27,23 @@ __all__ = [
]
+import logging
+
from email.utils import formataddr
from lazr.config import as_boolean
+from urllib2 import URLError
+from zope.component import getUtility
from mailman.config import config
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification, UserNotification
from mailman.interfaces.member import DeliveryMode
+from mailman.interfaces.templates import ITemplateLoader
from mailman.utilities.i18n import make
-from mailman.utilities.string import wrap
+from mailman.utilities.string import expand, wrap
+
+
+log = logging.getLogger('mailman.error')
@@ -50,12 +58,20 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
:param address: The address to respond to
:type address: string
:param language: the language of the response
- :type language: string
+ :type language: ILanguage
:param delivery_mode: the type of delivery the subscriber is getting
:type delivery_mode: DeliveryMode
"""
if mlist.welcome_message_uri:
- welcome = wrap(mlist.welcome_message_uri) + '\n'
+ try:
+ welcome_message = getUtility(ITemplateLoader).get(
+ mlist.welcome_message_uri)
+ except URLError:
+ log.exception('Welcome message URI not found ({0}): {1}'.format(
+ mlist.fqdn_listname, mlist.welcome_message_uri))
+ welcome = ''
+ else:
+ welcome = wrap(welcome_message)
else:
welcome = ''
# Find the IMember object which is subscribed to the mailing list, because
@@ -63,16 +79,15 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
member = mlist.members.get_member(address)
options_url = member.options_url
# Get the text from the template.
- text += make('subscribeack.txt',
- mailing_list=mlist,
- language=language.code,
- real_name=mlist.real_name,
- posting_address=mlist.fqdn_listname,
- listinfo_url=mlist.script_url('listinfo'),
- optionsurl=options_url,
- request_address=mlist.request_address,
- welcome=welcome,
- )
+ text = expand(welcome, dict(
+ fqdn_listname=mlist.fqdn_listname,
+ list_name=mlist.real_name,
+ listinfo_uri=mlist.script_url('listinfo'),
+ list_requests=mlist.request_address,
+ user_name=member.user.real_name,
+ user_address=address,
+ user_options_uri=options_url,
+ ))
if delivery_mode is not DeliveryMode.regular:
digmode = _(' (Digest mode)')
else:
diff --git a/src/mailman/app/templates.py b/src/mailman/app/templates.py
index 61880da12..a91231cfc 100644
--- a/src/mailman/app/templates.py
+++ b/src/mailman/app/templates.py
@@ -52,7 +52,7 @@ class MailmanHandler(urllib2.BaseHandler):
# Parse the full requested URL and be sure it's something we handle.
original_url = req.get_full_url()
parsed = urlparse(original_url)
- assert(parsed.scheme == 'mailman')
+ assert parsed.scheme == 'mailman'
# The path can contain one, two, or three components. Since no empty
# path components are legal, filter them out.
parts = filter(None, parsed.path.split('/'))
diff --git a/src/mailman/app/tests/test_notifications.py b/src/mailman/app/tests/test_notifications.py
new file mode 100644
index 000000000..74716246c
--- /dev/null
+++ b/src/mailman/app/tests/test_notifications.py
@@ -0,0 +1,101 @@
+# 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 notifications."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ ]
+
+
+import os
+import shutil
+import tempfile
+import unittest
+
+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.testing.helpers import get_queue_messages
+from mailman.testing.layers import ConfigLayer
+
+
+
+class TestNotifications(unittest.TestCase):
+ """Test notifications."""
+
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+ self._mlist.welcome_message_uri = 'mailman:///welcome.txt'
+ self._mlist.real_name = 'Test List'
+ self.var_dir = tempfile.mkdtemp()
+ config.push('template config', """\
+ [paths.testing]
+ template_dir: {0}/templates
+ """.format(self.var_dir))
+ # Populate the template directories with a few fake templates.
+ path = os.path.join(self.var_dir, 'templates', 'site', 'en')
+ os.makedirs(path)
+ with open(os.path.join(path, 'welcome.txt'), 'w') as fp:
+ print("""\
+Welcome to the $list_name mailing list.
+
+ Posting address: $fqdn_listname
+ Help and other requests: $list_requests
+ Your name: $user_name
+ Your address: $user_address
+ Your options: $user_options_uri""", file=fp)
+
+ def tearDown(self):
+ config.pop('template config')
+ 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)
+ message = messages[0].msg
+ self.assertEqual(str(message['subject']),
+ 'Welcome to the "Test List" mailing list')
+ try:
+ eq = self.assertMultiLineEqual
+ except AttributeError:
+ # Python 2.6
+ eq = self.assertEqual
+ eq(message.get_payload(), """\
+Welcome to the Test List mailing list.
+
+ Posting address: test@example.com
+ Help and other requests: test-request@example.com
+ Your name: Anne Person
+ Your address: anne@example.com
+ Your options: http://example.com/anne@example.com
+""")
diff --git a/src/mailman/model/docs/requests.rst b/src/mailman/model/docs/requests.rst
index cf4eb90ac..eca161de4 100644
--- a/src/mailman/model/docs/requests.rst
+++ b/src/mailman/model/docs/requests.rst
@@ -541,6 +541,7 @@ The subscription can also be accepted. This subscribes the address to the
mailing list.
>>> mlist.send_welcome_message = True
+ >>> mlist.welcome_message_uri = 'mailman:///welcome.txt'
>>> id_4 = moderator.hold_subscription(mlist,
... 'fperson@example.org', 'Frank Person',
... 'abcxyz', DeliveryMode.regular, 'en')
diff --git a/src/mailman/rest/docs/configuration.rst b/src/mailman/rest/docs/configuration.rst
index 5f59a1915..ea00b688c 100644
--- a/src/mailman/rest/docs/configuration.rst
+++ b/src/mailman/rest/docs/configuration.rst
@@ -99,7 +99,7 @@ all the writable attributes in one request.
... collapse_alternatives=False,
... reply_goes_to_list='point_to_list',
... send_welcome_message=False,
- ... welcome_message_uri='Welcome!',
+ ... welcome_message_uri='mailman:///welcome.txt',
... default_member_action='hold',
... default_nonmember_action='discard',
... generic_nonmember_action=2,
@@ -148,7 +148,7 @@ These values are changed permanently.
...
send_welcome_message: False
...
- welcome_message_uri: Welcome!
+ welcome_message_uri: mailman:///welcome.txt
If you use ``PUT`` to change a list's configuration, all writable attributes
must be included. It is an error to leave one or more out...
diff --git a/src/mailman/templates/en/subscribeack.txt b/src/mailman/templates/en/welcome.txt
index b39783737..503a422cd 100644
--- a/src/mailman/templates/en/subscribeack.txt
+++ b/src/mailman/templates/en/welcome.txt
@@ -1,22 +1,22 @@
-Welcome to the "$real_name" mailing list!
-$welcome
+Welcome to the "$list_name" mailing list!
+
To post to this list, send your email to:
- $posting_address
+ $fqdn_listname
General information about the mailing list is at:
- $listinfo_url
+ $listinfo_uri
If you ever want to unsubscribe or change your options (eg, switch to or
from digest mode, change your password, etc.), visit your subscription
page at:
- $optionsurl
+ $user_options_uri
You can also make such adjustments via email by sending a message to:
- $request_address
+ $list_requests
with the word 'help' in the subject or body (don't include the quotes), and
you will get back a message with instructions. You will need your password to
diff --git a/src/mailman/utilities/i18n.py b/src/mailman/utilities/i18n.py
index c02c6d5ba..3ef3a4077 100644
--- a/src/mailman/utilities/i18n.py
+++ b/src/mailman/utilities/i18n.py
@@ -58,20 +58,20 @@ def search(template_file, mlist=None, language=None):
"""Generator that provides file system search order.
This is Mailman's internal template search algorithm. The first locations
- searched are within the $var_dir/templates directory, allowing a site to
+ searched are within the $template_dir directory, allowing a site to
override a template for a specific mailing list, all the mailing lists in
a domain, or site-wide.
The <language> path component is variable, and described below.
* The list-specific language directory
- <var_dir>/templates/lists/<mlist.fqdn_listname>/<language>
+ $template_dir/lists/<mlist.fqdn_listname>/<language>
* The domain-specific language directory
- <var_dir>/templates/domains/<mlist.mail_host>/<language>
+ $template_dir/domains/<mlist.mail_host>/<language>
* The site-wide language directory
- <var_dir>/templates/site/<language>
+ $template_dir/site/<language>
The <language> path component is calculated as follows, in this order:
@@ -86,21 +86,21 @@ def search(template_file, mlist=None, language=None):
is 'de' and the `language` parameter is 'it', these locations are searched
in order:
- * <var_dir>/templates/lists/test@example.com/it/foo.txt
- * <var_dir>/templates/domains/example.com/it/foo.txt
- * <var_dir>/templates/site/it/foo.txt
+ * $template_dir/lists/test@example.com/it/foo.txt
+ * $template_dir/domains/example.com/it/foo.txt
+ * $template_dir/site/it/foo.txt
- * <var_dir>/templates/lists/test@example.com/de/foo.txt
- * <var_dir>/templates/domains/example.com/de/foo.txt
- * <var_dir>/templates/site/de/foo.txt
+ * $template_dir/lists/test@example.com/de/foo.txt
+ * $template_dir/domains/example.com/de/foo.txt
+ * $template_dir/site/de/foo.txt
- * <var_dir>/templates/lists/test@example.com/fr/foo.txt
- * <var_dir>/templates/domains/example.com/fr/foo.txt
- * <var_dir>/templates/site/fr/foo.txt
+ * $template_dir/lists/test@example.com/fr/foo.txt
+ * $template_dir/domains/example.com/fr/foo.txt
+ * $template_dir/site/fr/foo.txt
- * <var_dir>/templates/lists/test@example.com/en/foo.txt
- * <var_dir>/templates/domains/example.com/en/foo.txt
- * <var_dir>/templates/site/en/foo.txt
+ * $template_dir/lists/test@example.com/en/foo.txt
+ * $template_dir/domains/example.com/en/foo.txt
+ * $template_dir/site/en/foo.txt
After all those paths are searched, the final fallback is the English
template within the Mailman source tree.
@@ -114,13 +114,13 @@ def search(template_file, mlist=None, language=None):
if language is not None:
languages.append(language)
languages.reverse()
- # The non-language qualified $var_dir paths in search order.
- paths = [os.path.join(config.VAR_DIR, 'templates', 'site')]
+ # The non-language qualified $template_dir paths in search order.
+ paths = [os.path.join(config.TEMPLATE_DIR, 'site')]
if mlist is not None:
paths.append(os.path.join(
- config.VAR_DIR, 'templates', 'domains', mlist.mail_host))
+ config.TEMPLATE_DIR, 'domains', mlist.mail_host))
paths.append(os.path.join(
- config.VAR_DIR, 'templates', 'lists', mlist.fqdn_listname))
+ config.TEMPLATE_DIR, 'lists', mlist.fqdn_listname))
paths.reverse()
for language, path in product(languages, paths):
yield os.path.join(path, language, template_file)
diff --git a/src/mailman/utilities/string.py b/src/mailman/utilities/string.py
index c3bd3620c..7470bd476 100644
--- a/src/mailman/utilities/string.py
+++ b/src/mailman/utilities/string.py
@@ -197,7 +197,7 @@ def wrap(text, column=70, honor_leading_ws=True):
add_paragraph_break = False
paragraph_text = EMPTYSTRING.join(paragraph)
# Just copy the blank lines to the final set of paragraphs.
- if paragraph == NL:
+ if len(paragraph) == 0 or paragraph == NL:
wrapped_paragraphs.append(NL)
# Choose the wrapper based on whether the paragraph is indented or
# not. Also, do not wrap indented paragraphs if honor_leading_ws is