diff options
Diffstat (limited to 'src/mailman/chains')
| -rw-r--r-- | src/mailman/chains/builtin.py | 7 | ||||
| -rw-r--r-- | src/mailman/chains/docs/moderation.txt | 82 | ||||
| -rw-r--r-- | src/mailman/chains/moderation.py (renamed from src/mailman/chains/membermod.py) | 53 |
3 files changed, 80 insertions, 62 deletions
diff --git a/src/mailman/chains/builtin.py b/src/mailman/chains/builtin.py index c81f6700f..48e4bd535 100644 --- a/src/mailman/chains/builtin.py +++ b/src/mailman/chains/builtin.py @@ -51,8 +51,9 @@ class BuiltInChain: ('approved', LinkAction.jump, 'accept'), ('emergency', LinkAction.jump, 'hold'), ('loop', LinkAction.jump, 'discard'), - # Do all of the following before deciding whether to hold the message - # for moderation. + # Determine whether the member or nonmember has an action shortcut. + ('moderation', LinkAction.jump, 'moderation'), + # Do all of the following before deciding whether to hold the message. ('administrivia', LinkAction.defer, None), ('implicit-dest', LinkAction.defer, None), ('max-recipients', LinkAction.defer, None), @@ -62,8 +63,6 @@ class BuiltInChain: ('suspicious-header', LinkAction.defer, None), # Now if any of the above hit, jump to the hold chain. ('any', LinkAction.jump, 'hold'), - # Hold the message if the sender is a moderated member. - ('member-moderation', LinkAction.jump, 'member-moderation'), # Take a detour through the header matching chain, which we'll create # later. ('truth', LinkAction.detour, 'header-match'), diff --git a/src/mailman/chains/docs/moderation.txt b/src/mailman/chains/docs/moderation.txt index c95b8cac4..33bf63df9 100644 --- a/src/mailman/chains/docs/moderation.txt +++ b/src/mailman/chains/docs/moderation.txt @@ -8,14 +8,32 @@ moderator approval. >>> mlist = create_list('test@example.com') +Members and nonmembers have a *moderation action* which can shortcut the +normal moderation checks. The built-in chain does just a few checks first, +such as seeing if the message has a matching `Approved:` header, or if the +emergency flag has been set on the mailing list, or whether a mail loop has +been detected. + +After those, the moderation action for the sender is checked. Members +generally have a `defer` action, meaning the normal moderation checks are +done, but it is also common for first-time posters to have a `hold` action, +meaning that their messages are held for moderator approval for a while. + +Nonmembers almost always have a `hold` action, though some mailing lists may +choose to set this default action to `discard`, meaning their posts would be +immediately thrown away. + +XXX What about default nonmember actions when the poster has not been +registered as a nonmember? + Member moderation ================= -Posts by list members are moderated if the member's moderation flag is set. -The default setting for the moderation flag of new members is determined by -the mailing list's settings. By default, a mailing list is not set to -moderate new member postings. +Posts by list members are moderated if the member's moderation action is not +deferred. The default setting for the moderation action of new members is +determined by the mailing list's settings. By default, a mailing list is not +set to moderate new member postings. >>> from mailman.app.membership import add_member >>> from mailman.interfaces.member import DeliveryMode @@ -23,8 +41,8 @@ moderate new member postings. ... DeliveryMode.regular, 'en') >>> member <Member: Anne <anne@example.com> on test@example.com as MemberRole.member> - >>> member.is_moderated - False + >>> print member.moderation_action + Action.defer In order to find out whether the message is held or accepted, we can subscribe to Zope events that are triggered on each case. @@ -68,6 +86,7 @@ built-in chain. No rules hit and so the message is accepted. approved emergency loop + moderation administrivia implicit-dest max-recipients @@ -75,12 +94,14 @@ built-in chain. No rules hit and so the message is accepted. news-moderation no-subject suspicious-header - member-moderation -However, when Anne's moderation flag is set, and the list's member moderation -action is set to `hold`, her post is held for moderation. +However, when Anne's moderation action is set to `hold`, her post is held for +moderator approval. :: + >>> from mailman.interfaces.action import Action + >>> member.moderation_action = Action.hold + >>> msg = message_from_string("""\ ... From: anne@example.com ... To: test@example.com @@ -89,33 +110,21 @@ action is set to `hold`, her post is held for moderation. ... This is a test. ... """) - >>> member.is_moderated = True - >>> print mlist.member_moderation_action - Action.hold - >>> process(mlist, msg, {}, 'built-in') <mailman.chains.hold.HoldNotification ...> <mailman.chains.hold.HoldChain ...> Subject: badger Hits: - member-moderation + moderation Misses: approved emergency loop - administrivia - implicit-dest - max-recipients - max-size - news-moderation - no-subject - suspicious-header The list's member moderation action can also be set to `discard`... :: - >>> from mailman.interfaces.action import Action - >>> mlist.member_moderation_action = Action.discard + >>> member.moderation_action = Action.discard >>> msg = message_from_string("""\ ... From: anne@example.com @@ -130,22 +139,15 @@ The list's member moderation action can also be set to `discard`... <mailman.chains.discard.DiscardChain ...> Subject: cougar Hits: - member-moderation + moderation Misses: approved emergency loop - administrivia - implicit-dest - max-recipients - max-size - news-moderation - no-subject - suspicious-header ... or `reject`. - >>> mlist.member_moderation_action = Action.reject + >>> member.moderation_action = Action.reject >>> msg = message_from_string("""\ ... From: anne@example.com @@ -160,18 +162,18 @@ The list's member moderation action can also be set to `discard`... <mailman.chains.reject.RejectChain ...> Subject: dingo Hits: - member-moderation + moderation Misses: approved emergency loop - administrivia - implicit-dest - max-recipients - max-size - news-moderation - no-subject - suspicious-header + + +Nonmembers +========== + +XXX + .. Clean up >>> zope.event.subscribers.remove(on_chain) diff --git a/src/mailman/chains/membermod.py b/src/mailman/chains/moderation.py index 4a220b59d..1b5ab47b6 100644 --- a/src/mailman/chains/membermod.py +++ b/src/mailman/chains/moderation.py @@ -15,18 +15,30 @@ # You should have received a copy of the GNU General Public License along with # GNU Mailman. If not, see <http://www.gnu.org/licenses/>. -"""Member moderation chain. +"""Moderation chain. -When a member's moderation flag is set, the built-in chain jumps to this -chain, which just checks the mailing list's member moderation action. Based -on this value, one of the normal termination chains is jumped to. +When a member or nonmember posting to the mailing list has a moderation action +that is not `defer`, the built-in chain jumps to this chain. This chain then +determines the disposition of the message based on the member's or nonmember's +moderation action. + +For example, these actions jump to the appropriate terminal chain: + + * accept - the message is immediately accepted + * hold - the message is held for moderator approval + * reject - the message is bounced + * discard - the message is immediately thrown away + +Note that if the moderation action is `defer` then the normal decisions are +made as to the disposition of the message. `defer` is the default for +members, while `hold` is the default for nonmembers. """ from __future__ import absolute_import, unicode_literals __metaclass__ = type __all__ = [ - 'MemberModerationChain', + 'ModerationChain', ] @@ -40,33 +52,38 @@ from mailman.interfaces.chain import IChain, LinkAction -class MemberModerationChain: +class ModerationChain: """Dynamically produce a link jumping to the appropriate terminal chain. The terminal chain will be one of the Accept, Hold, Discard, or Reject - chains, based on the mailing list's member moderation action setting. + chains, based on the member's or nonmember's moderation action setting. """ implements(IChain) - name = 'member-moderation' - description = _('Member moderation chain') - is_abstract = False + name = 'moderation' + description = _('Moderation chain') def get_links(self, mlist, msg, msgdata): """See `IChain`.""" + # Get the moderation action from the message metadata. It can only be + # one of the expected values (i.e. not Action.defer). See the + # moderation.py rule for details. This is stored in the metadata as a + # string so that it can be stored in the pending table. + action = Action[msgdata.get('moderation_action')] # defer and accept are not valid moderation actions. - jump_chains = { + jump_chain = { + Action.accept: 'accept', + Action.discard: 'discard', Action.hold: 'hold', Action.reject: 'reject', - Action.discard: 'discard', - } - chain_name = jump_chains.get(mlist.member_moderation_action) - assert chain_name is not None, ( - '{0}: Invalid member_moderation_action: {1}'.format( - mlist.fqdn_listname, mlist.member_moderation_action)) + }.get(action) + assert jump_chain is not None, ( + '{0}: Invalid moderation action: {1} for sender: {2}'.format( + mlist.fqdn_listname, action, + msgdata.get('moderation_sender', '(unknown)'))) truth = config.rules['truth'] - chain = config.chains[chain_name] + chain = config.chains[jump_chain] return iter([ Link(truth, LinkAction.jump, chain), ]) |
