diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/app/notifications.py | 41 | ||||
| -rw-r--r-- | src/mailman/app/templates.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/tests/test_notifications.py | 101 | ||||
| -rw-r--r-- | src/mailman/model/docs/requests.rst | 1 | ||||
| -rw-r--r-- | src/mailman/rest/docs/configuration.rst | 4 | ||||
| -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.py | 40 | ||||
| -rw-r--r-- | src/mailman/utilities/string.py | 2 |
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 |
