summaryrefslogtreecommitdiff
path: root/src/mailman/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/core')
-rw-r--r--src/mailman/core/i18n.py18
-rw-r--r--src/mailman/core/pipelines.py2
-rw-r--r--src/mailman/core/tests/test_pipelines.py51
3 files changed, 63 insertions, 8 deletions
diff --git a/src/mailman/core/i18n.py b/src/mailman/core/i18n.py
index 69abe3b9d..d5aa06b5c 100644
--- a/src/mailman/core/i18n.py
+++ b/src/mailman/core/i18n.py
@@ -47,3 +47,21 @@ def initialize(application=None):
def handle_ConfigurationUpdatedEvent(event):
if isinstance(event, ConfigurationUpdatedEvent):
_.default = event.config.mailman.default_language
+
+
+@public
+def format_reasons(reasons):
+ """Translate and format hold and rejection reasons.
+
+ :param reasons: A list of reasons from the rules that hit. Each reason is
+ a string to be translated or a tuple consisting of a string with {}
+ replacements and one or more replacement values.
+ :returns: A list of the translated and formatted strings.
+ """
+ new_reasons = []
+ for reason in reasons:
+ if isinstance(reason, tuple):
+ new_reasons.append(_(reason[0]).format(*reason[1:]))
+ else:
+ new_reasons.append(_(reason))
+ return new_reasons
diff --git a/src/mailman/core/pipelines.py b/src/mailman/core/pipelines.py
index df07bc608..4265d24d1 100644
--- a/src/mailman/core/pipelines.py
+++ b/src/mailman/core/pipelines.py
@@ -55,7 +55,7 @@ def process(mlist, msg, msgdata, pipeline_name='built-in'):
except RejectMessage as error:
vlog.info(
'{} rejected by "{}" pipeline handler "{}": {}'.format(
- message_id, pipeline_name, handler.name, error.message))
+ message_id, pipeline_name, handler.name, str(error)))
bounce_message(mlist, msg, error)
diff --git a/src/mailman/core/tests/test_pipelines.py b/src/mailman/core/tests/test_pipelines.py
index 4ec55798f..3d4ae0ad2 100644
--- a/src/mailman/core/tests/test_pipelines.py
+++ b/src/mailman/core/tests/test_pipelines.py
@@ -48,8 +48,11 @@ class DiscardingHandler:
class RejectHandler:
name = 'rejecting'
+ def __init__(self, message):
+ self.message = message
+
def process(self, mlist, msg, msgdata):
- raise RejectMessage('by test handler')
+ raise RejectMessage(self.message)
@implementer(IPipeline)
@@ -66,8 +69,11 @@ class RejectingPipeline:
name = 'test-rejecting'
description = 'Rejectinging test pipeline'
+ def __init__(self):
+ self.message = 'by test handler'
+
def __iter__(self):
- yield RejectHandler()
+ yield RejectHandler(self.message)
class TestPostingPipeline(unittest.TestCase):
@@ -109,18 +115,49 @@ testing
'"discarding": by test handler'))
def test_rejecting_pipeline(self):
- # If a handler in the pipeline raises DiscardMessage, the message will
- # be thrown away, but with a log message.
+ # If a handler in the pipeline raises RejectMessage, the post will
+ # be bounced with a log message.
mark = LogFileMark('mailman.vette')
process(self._mlist, self._msg, {}, 'test-rejecting')
line = mark.readline()[:-1]
- self.assertTrue(line.endswith(
+ self.assertEqual(
+ line[-80:],
+ '<ant> rejected by "test-rejecting" pipeline handler '
+ '"rejecting": by test handler',
+ line)
+ # In the rejection case, the original message will also be in the
+ # virgin queue.
+ items = get_queue_messages('virgin', expected_count=1)
+ self.assertEqual(
+ str(items[0].msg.get_payload(1).get_payload(0)['subject']),
+ 'a test')
+ # The first payload contains the rejection reason.
+ payload = items[0].msg.get_payload(0).get_payload()
+ self.assertEqual(payload, 'by test handler')
+
+ def test_rejecting_pipeline_without_message(self):
+ # Similar to above, but without a rejection message.
+ pipeline = config.pipelines['test-rejecting']
+ message = pipeline.message
+ self.addCleanup(setattr, pipeline, 'message', message)
+ pipeline.message = None
+ mark = LogFileMark('mailman.vette')
+ process(self._mlist, self._msg, {}, 'test-rejecting')
+ line = mark.readline()[:-1]
+ self.assertEqual(
+ line[-91:],
'<ant> rejected by "test-rejecting" pipeline handler '
- '"rejecting": by test handler'))
+ '"rejecting": [No details are available]',
+ line)
# In the rejection case, the original message will also be in the
# virgin queue.
items = get_queue_messages('virgin', expected_count=1)
- self.assertEqual(str(items[0].msg['subject']), 'a test')
+ self.assertEqual(
+ str(items[0].msg.get_payload(1).get_payload(0)['subject']),
+ 'a test')
+ # The first payload contains the rejection reason.
+ payload = items[0].msg.get_payload(0).get_payload()
+ self.assertEqual(payload, '[No details are available]')
def test_decorate_bulk(self):
# Ensure that bulk postings get decorated with the footer.