diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/rules/moderation.py | 119 |
1 files changed, 53 insertions, 66 deletions
diff --git a/src/mailman/rules/moderation.py b/src/mailman/rules/moderation.py index 3f10e31bf..b6b33f720 100644 --- a/src/mailman/rules/moderation.py +++ b/src/mailman/rules/moderation.py @@ -30,6 +30,29 @@ from zope.component import getUtility from zope.interface import implementer +def _find_sender_member(mlist, msg): + # For every sender email in the message, try to find a member associated + # with that email. + # + # First, check the sender email directly. If it's a member, we're done. + # + # Next, check to see if the sender email is linked to an existing user, + # and if so, check to see if any of the addresses linked to that user is a + # member. + user_manager = getUtility(IUserManager) + for sender in msg.senders: + member = mlist.members.get_member(sender) + if member is not None: + return member + user = user_manager.get_user(sender) + if user is not None: + for address in user.addresses: + member = mlist.members.get_member(address.email) + if member is not None: + return member + return None + + @public @implementer(IRule) class MemberModeration: @@ -44,47 +67,27 @@ class MemberModeration: # The MemberModeration rule misses unconditionally if any of the # senders are banned. ban_manager = IBanManager(mlist) - user_manager = getUtility(IUserManager) for sender in msg.senders: if ban_manager.is_banned(sender): return False - # For each sender address, try to find a member associated with the - # email address. Start by checking the sender email directly. If the - # sender email is not a member, try to find the user linked to the - # email, and then check to see if *that* user, or any of the addresses - # linked to that user is a member. This rule hits of we find a member - # and their moderation action is not to defer. - for sender in msg.senders: - # Is the sender email itself a member? - member = mlist.members.get_member(sender) - if member is None: - # Is the sender email linked to a user? - user = user_manager.get_user(sender) - if user is not None: - # Are any of the emails linked to this user a member? - for address in user.addresses: - member = mlist.members.get_member(address.email) - if member is not None: - # We found a member, so we don't need to check any - # of the other linked addresses. - break - if member is None: - return False - action = (mlist.default_member_action - if member.moderation_action is None - else member.moderation_action) - if action is Action.defer: - # The regular moderation rules apply. - return False - elif action is not None: - # We must stringify the moderation action so that it can be - # stored in the pending request table. - msgdata['moderation_action'] = action.name - msgdata['moderation_sender'] = sender - msgdata.setdefault('moderation_reasons', []).append( - # This will get translated at the point of use. - 'The message comes from a moderated member') - return True + member = _find_sender_member(mlist, msg) + if member is None: + return False + action = (mlist.default_member_action + if member.moderation_action is None + else member.moderation_action) + if action is Action.defer: + # The regular moderation rules apply. + return False + elif action is not None: + # We must stringify the moderation action so that it can be + # stored in the pending request table. + msgdata['moderation_action'] = action.name + msgdata['moderation_sender'] = sender + msgdata.setdefault('moderation_reasons', []).append( + # This will get translated at the point of use. + 'The message comes from a moderated member') + return True # The sender is not a member so this rule does not match. return False @@ -113,43 +116,27 @@ class NonmemberModeration: for sender in msg.senders: if ban_manager.is_banned(sender): return False - # Every sender must somehow be a member or nonmember. The sender - # email can have one of those roles directly, or a user that the email - # is linked to can have one of those roles indirectly, or any address - # linked to one of those users can have one of those roles. - # - # If the sender is not somehow a member or nonmember, make them a - # nonmember. We maintain a record of which senders are members, and - # then the ones that aren't are made nonmembers. - found_linked_membership = set() + # Every sender email must be a member or nonmember directly. If it is + # neither, make the email a nonmembers. for sender in msg.senders: - member = mlist.members.get_member(sender) - if member is None: - user = user_manager.get_user(sender) - if user is not None: - for address in user.addresses: - if mlist.members.get_member(address.email) is not None: - found_linked_membership.add(sender) - else: - found_linked_membership.add(sender) - # Now we know whether the sender is somehow linked to a member or - # not. If not, and the email also isn't already a nonmember, make - # them a nonmember. - if (mlist.nonmembers.get_member(sender) is None - and sender not in found_linked_membership): # noqa + if (mlist.members.get_member(sender) is None + and mlist.nonmembers.get_member(sender) is None): # noqa + # The email must already be registered, since this happens in + # the incoming runner itself. address = user_manager.get_address(sender) assert address is not None, ( 'Posting address is not registered: {}'.format(sender)) mlist.subscribe(address, MemberRole.nonmember) - # If a membership is found, the MemberModeration rule takes precedence. - for sender in msg.senders: - if sender in found_linked_membership: - return False + # Check to see if any of the sender emails is already a member. If + # so, then this rule misses. + member = _find_sender_member(mlist, msg) + if member is not None: + return False # Do nonmember moderation check. for sender in msg.senders: nonmember = mlist.nonmembers.get_member(sender) assert nonmember is not None, ( - 'Sender not added to the nonmembers: {}'.format(sender)) + "sender didn't get subscribed as a nonmember".format(sender)) # Check the '*_these_nonmembers' properties first. XXX These are # legacy attributes from MM2.1; their database type is 'pickle' and # they should eventually get replaced. |
