diff options
| -rw-r--r-- | src/mailman/database/schema/postgres.sql | 2 | ||||
| -rw-r--r-- | src/mailman/database/schema/sqlite.sql | 2 | ||||
| -rw-r--r-- | src/mailman/interfaces/mailinglist.py | 20 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 2 | ||||
| -rw-r--r-- | src/mailman/runners/incoming.py | 5 | ||||
| -rw-r--r-- | src/mailman/runners/tests/test_incoming.py | 94 |
6 files changed, 123 insertions, 2 deletions
diff --git a/src/mailman/database/schema/postgres.sql b/src/mailman/database/schema/postgres.sql index bd7ef3f6b..2e9ba249f 100644 --- a/src/mailman/database/schema/postgres.sql +++ b/src/mailman/database/schema/postgres.sql @@ -84,6 +84,8 @@ CREATE TABLE mailinglist ( nondigestable BOOLEAN, nonmember_rejection_notice TEXT, obscure_addresses BOOLEAN, + owner_chain TEXT, + owner_pipeline TEXT, personalize INTEGER, post_id INTEGER, posting_chain TEXT, diff --git a/src/mailman/database/schema/sqlite.sql b/src/mailman/database/schema/sqlite.sql index 37b6ed8f2..e6211bf53 100644 --- a/src/mailman/database/schema/sqlite.sql +++ b/src/mailman/database/schema/sqlite.sql @@ -180,6 +180,8 @@ CREATE TABLE mailinglist ( nondigestable BOOLEAN, nonmember_rejection_notice TEXT, obscure_addresses BOOLEAN, + owner_chain TEXT, + owner_pipeline TEXT, personalize INTEGER, post_id INTEGER, posting_chain TEXT, diff --git a/src/mailman/interfaces/mailinglist.py b/src/mailman/interfaces/mailinglist.py index d92bae464..bced070d3 100644 --- a/src/mailman/interfaces/mailinglist.py +++ b/src/mailman/interfaces/mailinglist.py @@ -382,7 +382,7 @@ class IMailingList(Interface): # Processing. posting_chain = Attribute( - """This mailing list's moderation chain. + """This mailing list's posting moderation chain. When messages are posted to a mailing list, it first goes through a moderation chain to determine whether the message will be accepted. @@ -397,6 +397,24 @@ class IMailingList(Interface): This attribute names a pipeline for postings, which must exist. """) + owner_chain = Attribute( + """This mailing list's owner moderation chain. + + When messages are posted to the owners of a mailing list, it first + goes through a moderation chain to determine whether the message will + be accepted. This attribute names a chain for postings, which must + exist. + """) + + owner_pipeline = Attribute( + """This mailing list's owner posting pipeline. + + Every mailing list has a processing pipeline that messages flow + through once they've been accepted for posting to the owners of a + mailing list. This attribute names a pipeline for postings, which + must exist. + """) + data_path = Attribute( """The file system path to list-specific data. diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 76f88caa7..e397d59d6 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -168,6 +168,8 @@ class MailingList(Model): nondigestable = Bool() nonmember_rejection_notice = Unicode() obscure_addresses = Bool() + owner_chain = Unicode() + owner_pipeline = Unicode() personalize = Enum(Personalization) post_id = Int() posting_chain = Unicode() diff --git a/src/mailman/runners/incoming.py b/src/mailman/runners/incoming.py index 7072f9bcc..d8db926c7 100644 --- a/src/mailman/runners/incoming.py +++ b/src/mailman/runners/incoming.py @@ -61,6 +61,9 @@ class IncomingRunner(Runner): pass config.db.commit() # Process the message through the mailing list's start chain. - process(mlist, msg, msgdata, mlist.posting_chain) + start_chain = (mlist.owner_chain + if msgdata.get('to_owner', False) + else mlist.posting_chain) + process(mlist, msg, msgdata, start_chain) # Do not keep this message queued. return False diff --git a/src/mailman/runners/tests/test_incoming.py b/src/mailman/runners/tests/test_incoming.py new file mode 100644 index 000000000..5a0d82765 --- /dev/null +++ b/src/mailman/runners/tests/test_incoming.py @@ -0,0 +1,94 @@ +# 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 the incoming queue runner.""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + 'TestIncoming', + ] + + +import unittest + +from mailman.app.lifecycle import create_list +from mailman.chains.base import TerminalChainBase +from mailman.config import config +from mailman.runners.incoming import IncomingRunner +from mailman.testing.helpers import ( + get_queue_messages, + make_testable_runner, + specialized_message_from_string as mfs) +from mailman.testing.layers import ConfigLayer + + + +class Chain(TerminalChainBase): + name = 'test' + description = 'a test chain' + + def __init__(self, marker): + self._marker = marker + + def _process(self, mlist, msg, msgdata): + msgdata['marker'] = self._marker + config.switchboards['out'].enqueue(msg, msgdata) + + + +class TestIncoming(unittest.TestCase): + """Test the incoming queue runner.""" + + layer = ConfigLayer + + def setUp(self): + self._mlist = create_list('test@example.com') + self._mlist.posting_chain = 'test posting' + self._mlist.owner_chain = 'test owner' + config.chains['test posting'] = Chain('posting') + config.chains['test owner'] = Chain('owner') + self._in = make_testable_runner(IncomingRunner, 'in') + self._msg = mfs("""\ +From: anne@example.com +To: test@example.com + +""") + + def tearDown(self): + del config.chains['test posting'] + del config.chains['test owner'] + + def test_posting(self): + # A message posted to the list goes through the posting chain. + msgdata = dict(listname='test@example.com') + config.switchboards['in'].enqueue(self._msg, msgdata) + self._in.run() + messages = get_queue_messages('out') + self.assertEqual(len(messages), 1) + self.assertEqual(messages[0].msgdata.get('marker'), 'posting') + + def test_owner(self): + # A message posted to the list goes through the posting chain. + msgdata = dict(listname='test@example.com', + to_owner=True) + config.switchboards['in'].enqueue(self._msg, msgdata) + self._in.run() + messages = get_queue_messages('out') + self.assertEqual(len(messages), 1) + self.assertEqual(messages[0].msgdata.get('marker'), 'owner') |
