summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/docs/NEWS.rst7
-rw-r--r--src/mailman/handlers/decorate.py14
-rw-r--r--src/mailman/handlers/docs/decorate.rst10
-rw-r--r--src/mailman/handlers/tests/test_decorate.py89
4 files changed, 119 insertions, 1 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index 341f22f0a..0f778c494 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -52,6 +52,13 @@ Internal API
* A handful of unused legacy exceptions have been removed. The redundant
`MailmanException` has been removed; use `MailmanError` everywhere.
+Message handling
+----------------
+ * New placeholders have been added for message headers and footers. You can
+ use a placeholder of the format `$<archiver-name>_url` to insert the
+ permalink to the message in the named archiver, for any archiver enabled
+ for the mailing list. Given by Abhilash Raj.
+
REST
----
* REST API version 3.1 introduced. Mostly backward compatible with version
diff --git a/src/mailman/handlers/decorate.py b/src/mailman/handlers/decorate.py
index 7f09c74e4..1d752cee5 100644
--- a/src/mailman/handlers/decorate.py
+++ b/src/mailman/handlers/decorate.py
@@ -31,6 +31,7 @@ from email.mime.text import MIMEText
from mailman.core.i18n import _
from mailman.email.message import Message
from mailman.interfaces.handler import IHandler
+from mailman.interfaces.mailinglist import IListArchiverSet
from mailman.interfaces.templates import ITemplateLoader
from mailman.utilities.string import expand
from urllib.error import URLError
@@ -59,19 +60,30 @@ def process(mlist, msg, msgdata):
if member.user.display_name
else member.address.original_email)
d['user_optionsurl'] = member.options_url
+ # Calculate the archiver permalink substitution variables. This provides
+ # the $<archive-name>_url placeholder for every enabled archiver.
+ for archiver in IListArchiverSet(mlist).archivers:
+ if archiver.is_enabled:
+ # Get the permalink of the message from the archiver.
+ archive_url = archiver.system_archiver.permalink(mlist, msg)
+ if archive_url is not None:
+ placeholder = '{}_url'.format(archiver.system_archiver.name)
+ d[placeholder] = archive_url
# These strings are descriptive for the log file and shouldn't be i18n'd
d.update(msgdata.get('decoration-data', {}))
try:
header = decorate(mlist, mlist.header_uri, d)
except URLError:
+ header = None
log.exception('Header decorator URI not found ({0}): {1}'.format(
mlist.fqdn_listname, mlist.header_uri))
try:
footer = decorate(mlist, mlist.footer_uri, d)
except URLError:
+ footer = None
log.exception('Footer decorator URI not found ({0}): {1}'.format(
mlist.fqdn_listname, mlist.footer_uri))
- # Escape hatch if both the footer and header are empty
+ # Escape hatch if both the footer and header are empty or None.
if not header and not footer:
return
# Be MIME smart here. We only attach the header and footer by
diff --git a/src/mailman/handlers/docs/decorate.rst b/src/mailman/handlers/docs/decorate.rst
index bc98d3d28..e6199f8e0 100644
--- a/src/mailman/handlers/docs/decorate.rst
+++ b/src/mailman/handlers/docs/decorate.rst
@@ -122,6 +122,16 @@ will remain in the header or footer unchanged.
$dummy footer
+Adding archiver permalink URLs in the message footer
+====================================================
+
+You can add links to archived messages in the footer using special placeholder
+variables. For all available and enabled archiver for the mailing list, use a
+placeholder of the format ``$<archiver_name>_url``. For example, if you have
+HyperKitty enabled you can add ``${hyperkitty_url}`` to point to the message
+in HyperKitty.
+
+
Handling RFC 3676 'format=flowed' parameters
============================================
diff --git a/src/mailman/handlers/tests/test_decorate.py b/src/mailman/handlers/tests/test_decorate.py
new file mode 100644
index 000000000..c8aba63db
--- /dev/null
+++ b/src/mailman/handlers/tests/test_decorate.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2014-2015 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 the decorate handler."""
+
+__all__ = [
+ 'TestDecorate',
+ ]
+
+
+import os
+import shutil
+import tempfile
+import unittest
+
+from mailman.app.lifecycle import create_list
+from mailman.config import config
+from mailman.handlers import decorate
+from mailman.interfaces.archiver import IArchiver
+from mailman.testing.helpers import specialized_message_from_string as mfs
+from mailman.testing.layers import ConfigLayer
+from zope.interface import implementer
+
+
+
+@implementer(IArchiver)
+class TestArchiver:
+ """A test archiver"""
+
+ name = 'testarchiver'
+ is_enabled = False
+
+ @staticmethod
+ def permalink(mlist, msg):
+ return 'http://example.com/link_to_message'
+
+
+
+class TestDecorate(unittest.TestCase):
+ """Test the cook_headers handler."""
+
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+ self._msg = mfs("""\
+To: test@example.com
+From: aperson@example.com
+Message-ID: <somerandomid.example.com>
+Content-Type: text/plain;
+
+This is a test message.
+""")
+ template_dir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, template_dir)
+ site_dir = os.path.join(template_dir, 'site', 'en')
+ os.makedirs(site_dir)
+ config.push('archiver', """\
+ [paths.testing]
+ template_dir: {}
+ [archiver.testarchiver]
+ class: mailman.handlers.tests.test_decorate.TestArchiver
+ enable: yes
+ """.format(template_dir))
+ self.addCleanup(config.pop, 'archiver')
+ self.footer_path = os.path.join(site_dir, 'myfooter.txt')
+
+ def test_decorate_footer_with_archive_url(self):
+ with open(self.footer_path, 'w', encoding='utf-8') as fp:
+ print('${testarchiver_url}', file=fp)
+ self._mlist.footer_uri = 'mailman:///myfooter.txt'
+ self._mlist.preferred_language = 'en'
+ decorate.process(self._mlist, self._msg, {})
+ self.assertIn('http://example.com/link_to_message',
+ self._msg.as_string())