summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAurélien Bompard2016-02-09 12:23:38 +0100
committerBarry Warsaw2016-03-31 18:29:27 -0400
commit71cfeda5fb51c49fd87b6d34e00221a3725b9ec0 (patch)
treed571db90e7010643ea7cca81ab91eaee89e0f378 /src
parent011d278abcc25d417673f70a4eac0a8a78137d95 (diff)
downloadmailman-71cfeda5fb51c49fd87b6d34e00221a3725b9ec0.tar.gz
mailman-71cfeda5fb51c49fd87b6d34e00221a3725b9ec0.tar.zst
mailman-71cfeda5fb51c49fd87b6d34e00221a3725b9ec0.zip
Members and nonmembers moderation action fallback
Members and nonmember's moderation action should be None by default, and in that case the moderation rule should fallback to the mailing list's default action. Fixes: #189
Diffstat (limited to 'src')
-rw-r--r--src/mailman/chains/docs/moderation.rst29
-rw-r--r--src/mailman/model/docs/membership.rst23
-rw-r--r--src/mailman/model/member.py10
-rw-r--r--src/mailman/model/tests/test_member.py21
-rw-r--r--src/mailman/rest/docs/addresses.rst5
-rw-r--r--src/mailman/rest/docs/membership.rst50
-rw-r--r--src/mailman/rest/members.py4
-rw-r--r--src/mailman/rules/docs/moderation.rst17
-rw-r--r--src/mailman/rules/moderation.py9
-rw-r--r--src/mailman/rules/tests/test_moderation.py57
-rw-r--r--src/mailman/utilities/importer.py2
-rw-r--r--src/mailman/utilities/tests/test_import.py5
12 files changed, 144 insertions, 88 deletions
diff --git a/src/mailman/chains/docs/moderation.rst b/src/mailman/chains/docs/moderation.rst
index cd0a8eb26..2415b8f4b 100644
--- a/src/mailman/chains/docs/moderation.rst
+++ b/src/mailman/chains/docs/moderation.rst
@@ -33,12 +33,7 @@ determined by the mailing list's settings. By default, a mailing list is not
set to moderate new member postings.
::
- >>> from mailman.testing.helpers import subscribe
- >>> member = subscribe(mlist, 'Anne', email='anne@example.com')
- >>> member
- <Member: Anne Person <anne@example.com> on test@example.com
- as MemberRole.member>
- >>> print(member.moderation_action)
+ >>> print(mlist.default_member_action)
Action.defer
In order to find out whether the message is held or accepted, we can subscribe
@@ -58,6 +53,18 @@ to Zope events that are triggered on each case.
... for miss in event.msgdata.get('rule_misses', []):
... print(' ', miss)
+The user Anne will be a list member. A list member's default moderation action
+is ``None``, meaning that it will use the mailing list's
+``default_member_action``.
+
+ >>> from mailman.testing.helpers import subscribe
+ >>> member = subscribe(mlist, 'Anne', email='anne@example.com')
+ >>> member
+ <Member: Anne Person <anne@example.com> on test@example.com
+ as MemberRole.member>
+ >>> print(member.moderation_action is None)
+ True
+
Anne's post to the mailing list runs through the incoming runner's default
built-in chain. No rules hit and so the message is accepted.
::
@@ -173,8 +180,8 @@ Nonmembers
==========
Registered nonmembers are handled very similarly to members, the main
-difference being that they usually have a default moderation action. This is
-how the incoming runner adds sender addresses as nonmembers.
+difference being that the mailing list's default moderation action is
+different. This is how the incoming runner adds sender addresses as nonmembers.
>>> from zope.component import getUtility
>>> from mailman.interfaces.usermanager import IUserManager
@@ -211,5 +218,11 @@ moderator approval.
>>> nonmember = mlist.nonmembers.get_member('bart@example.com')
>>> nonmember
<Member: bart@example.com on test@example.com as MemberRole.nonmember>
+
+A nonmember's default moderation action is ``None``, meaning that it will use
+the mailing list's ``default_nonmember_action``.
+
>>> print(nonmember.moderation_action)
+ None
+ >>> print(mlist.default_nonmember_action)
Action.hold
diff --git a/src/mailman/model/docs/membership.rst b/src/mailman/model/docs/membership.rst
index 0fd748d6a..c8452abf0 100644
--- a/src/mailman/model/docs/membership.rst
+++ b/src/mailman/model/docs/membership.rst
@@ -273,23 +273,26 @@ automatically accepted for posting to the mailing list.
aperson@example.com MemberRole.owner Action.accept
bperson@example.com MemberRole.moderator Action.accept
-By default, members have a *deferred* action which specifies that the posting
-should go through the normal moderation checks.
+By default, members and nonmembers have their action set to None, meaning that
+the mailing list's ``default_member_action`` or ``default_nonmember_action``
+will be used.
>>> for member in sorted(mlist.members.members,
... key=attrgetter('address.email')):
... print(member.address.email, member.role, member.moderation_action)
- aperson@example.com MemberRole.member Action.defer
- bperson@example.com MemberRole.member Action.defer
- cperson@example.com MemberRole.member Action.defer
- hperson@example.com MemberRole.member Action.defer
- iperson@example.com MemberRole.member Action.defer
-
-Postings by nonmembers are held for moderator approval by default.
+ aperson@example.com MemberRole.member None
+ bperson@example.com MemberRole.member None
+ cperson@example.com MemberRole.member None
+ hperson@example.com MemberRole.member None
+ iperson@example.com MemberRole.member None
>>> for member in mlist.nonmembers.members:
... print(member.address.email, member.role, member.moderation_action)
- fperson@example.com MemberRole.nonmember Action.hold
+ fperson@example.com MemberRole.nonmember None
+
+The mailing list's default action for members is *deferred*, which specifies
+that the posting should go through the normal moderation checks. Its default
+action for nonmembers is to hold for moderator approval.
Changing subscriptions
diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py
index 99f2de9b8..a6555c0fe 100644
--- a/src/mailman/model/member.py
+++ b/src/mailman/model/member.py
@@ -76,14 +76,10 @@ class Member(Model):
raise ValueError('subscriber must be a user or address')
if role in (MemberRole.owner, MemberRole.moderator):
self.moderation_action = Action.accept
- elif role is MemberRole.member:
- self.moderation_action = getUtility(IListManager).get_by_list_id(
- list_id).default_member_action
else:
- assert role is MemberRole.nonmember, (
- 'Invalid MemberRole: {}'.format(role))
- self.moderation_action = getUtility(IListManager).get_by_list_id(
- list_id).default_nonmember_action
+ assert role in (MemberRole.member, MemberRole.nonmember), (
+ 'Invalid MemberRole: {0}'.format(role))
+ self.moderation_action = None
def __repr__(self):
return '<Member: {} on {} as {}>'.format(
diff --git a/src/mailman/model/tests/test_member.py b/src/mailman/model/tests/test_member.py
index 3a24d9680..51402b659 100644
--- a/src/mailman/model/tests/test_member.py
+++ b/src/mailman/model/tests/test_member.py
@@ -20,6 +20,7 @@
import unittest
from mailman.app.lifecycle import create_list
+from mailman.interfaces.action import Action
from mailman.interfaces.member import MemberRole, MembershipError
from mailman.interfaces.user import UnverifiedAddressError
from mailman.interfaces.usermanager import IUserManager
@@ -100,3 +101,23 @@ class TestMember(unittest.TestCase):
member = self._mlist.members.get_member('anne@example.com')
member.unsubscribe()
self.assertEqual(len(list(self._mlist.members.members)), 0)
+
+ def test_default_moderation_action(self):
+ # Owners and moderators have their posts accepted, members and
+ # nonmembers default to the mailing list's action for their type.
+ anne = self._usermanager.create_user('anne@example.com')
+ bart = self._usermanager.create_user('bart@example.com')
+ cris = self._usermanager.create_user('cris@example.com')
+ dana = self._usermanager.create_user('dana@example.com')
+ set_preferred(anne)
+ set_preferred(bart)
+ set_preferred(cris)
+ set_preferred(dana)
+ anne_member = self._mlist.subscribe(anne, MemberRole.owner)
+ bart_member = self._mlist.subscribe(bart, MemberRole.moderator)
+ cris_member = self._mlist.subscribe(cris, MemberRole.member)
+ dana_member = self._mlist.subscribe(dana, MemberRole.nonmember)
+ self.assertEqual(anne_member.moderation_action, Action.accept)
+ self.assertEqual(bart_member.moderation_action, Action.accept)
+ self.assertIsNone(cris_member.moderation_action)
+ self.assertIsNone(dana_member.moderation_action)
diff --git a/src/mailman/rest/docs/addresses.rst b/src/mailman/rest/docs/addresses.rst
index c850503c4..e5dff0f7c 100644
--- a/src/mailman/rest/docs/addresses.rst
+++ b/src/mailman/rest/docs/addresses.rst
@@ -379,7 +379,6 @@ Elle can get her memberships for each of her email addresses.
http_etag: "..."
list_id: ant.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/4
@@ -390,7 +389,6 @@ Elle can get her memberships for each of her email addresses.
http_etag: "..."
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/4
@@ -422,7 +420,6 @@ does not show up in the list of memberships for his other address.
http_etag: "..."
list_id: ant.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/4
@@ -433,7 +430,6 @@ does not show up in the list of memberships for his other address.
http_etag: "..."
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/4
@@ -450,7 +446,6 @@ does not show up in the list of memberships for his other address.
http_etag: "..."
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/4
diff --git a/src/mailman/rest/docs/membership.rst b/src/mailman/rest/docs/membership.rst
index 3d2d9a010..ec8765d68 100644
--- a/src/mailman/rest/docs/membership.rst
+++ b/src/mailman/rest/docs/membership.rst
@@ -50,7 +50,6 @@ the REST interface.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -67,7 +66,6 @@ Bart's specific membership can be accessed directly:
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -88,7 +86,6 @@ the REST interface.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -99,7 +96,6 @@ the REST interface.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -123,7 +119,6 @@ subscribes, she is returned first.
http_etag: ...
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -134,7 +129,6 @@ subscribes, she is returned first.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -145,7 +139,6 @@ subscribes, she is returned first.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -175,7 +168,6 @@ User ids are different than member ids.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -186,7 +178,6 @@ User ids are different than member ids.
http_etag: ...
list_id: ant.example.com
member_id: 5
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
@@ -197,7 +188,6 @@ User ids are different than member ids.
http_etag: ...
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -208,7 +198,6 @@ User ids are different than member ids.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -219,7 +208,6 @@ User ids are different than member ids.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -238,7 +226,6 @@ We can also get just the members of a single mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -249,7 +236,6 @@ We can also get just the members of a single mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 5
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
@@ -276,7 +262,6 @@ page.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -295,7 +280,6 @@ This works with members of a single list as well as with all members.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -353,7 +337,6 @@ mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -364,7 +347,6 @@ mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 5
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
@@ -386,7 +368,6 @@ mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -397,7 +378,6 @@ mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -408,7 +388,6 @@ mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -467,7 +446,6 @@ example, we can search for all the memberships of a particular address.
http_etag: ...
list_id: ant.example.com
member_id: 4
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
@@ -478,7 +456,6 @@ example, we can search for all the memberships of a particular address.
http_etag: ...
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -498,7 +475,6 @@ Or, we can find all the memberships for a particular mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 3
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -509,7 +485,6 @@ Or, we can find all the memberships for a particular mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 1
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -520,7 +495,6 @@ Or, we can find all the memberships for a particular mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -553,7 +527,6 @@ list.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -585,7 +558,6 @@ Or, we can find all the memberships for an address with a specific role.
http_etag: ...
list_id: ant.example.com
member_id: 5
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
@@ -596,7 +568,6 @@ Or, we can find all the memberships for an address with a specific role.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -618,7 +589,6 @@ Finally, we can search for a specific member given all three criteria.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -640,7 +610,6 @@ Search can also be performed using HTTP GET queries.
http_etag: ...
list_id: bee.example.com
member_id: 2
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -699,7 +668,6 @@ Elly is now a known user, and a member of the mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 8
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/8
user: http://localhost:9001/3.0/users/5
@@ -746,7 +714,6 @@ list with her preferred address.
http_etag: "..."
list_id: ant.example.com
member_id: 9
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/9
user: http://localhost:9001/3.0/users/6
@@ -772,7 +739,6 @@ the new address.
http_etag: "..."
list_id: ant.example.com
member_id: 9
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/9
user: http://localhost:9001/3.0/users/6
@@ -840,7 +806,6 @@ addresses.
http_etag: "..."
list_id: ant.example.com
member_id: 10
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/10
user: http://localhost:9001/3.0/users/7
@@ -852,7 +817,6 @@ addresses.
http_etag: "..."
list_id: bee.example.com
member_id: 11
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/11
user: http://localhost:9001/3.0/users/7
@@ -911,7 +875,6 @@ his membership ids have not changed.
http_etag: "..."
list_id: ant.example.com
member_id: 10
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/10
user: http://localhost:9001/3.0/users/7
@@ -922,7 +885,6 @@ his membership ids have not changed.
http_etag: "..."
list_id: bee.example.com
member_id: 11
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/11
user: http://localhost:9001/3.0/users/7
@@ -952,7 +914,6 @@ mode of delivery.
http_etag: "..."
list_id: bee.example.com
member_id: 11
- moderation_action: defer
role: member
self_link: http://localhost:9001/3.0/members/11
user: http://localhost:9001/3.0/users/7
@@ -970,9 +931,14 @@ The moderation action for a member can be changed by PATCH'ing the
>>> dump_json('http://localhost:9001/3.0/members/10')
address: http://localhost:9001/3.0/addresses/hperson@example.com
- ...
- moderation_action: defer
- ...
+ delivery_mode: regular
+ email: hperson@example.com
+ http_etag: "6d544208d60e578189fc023748f1ec467290abb5"
+ list_id: ant.example.com
+ member_id: 10
+ role: member
+ self_link: http://localhost:9001/3.0/members/10
+ user: http://localhost:9001/3.0/users/7
>>> dump_json('http://localhost:9001/3.0/members/10', {
... 'moderation_action': 'hold',
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index b56fa3c8d..c842ccd7d 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -61,10 +61,12 @@ class _MemberBase(CollectionMixin):
email=member.address.email,
list_id=member.list_id,
member_id=member_id,
- moderation_action=member.moderation_action,
role=role,
self_link=self.api.path_to('members/{}'.format(member_id)),
)
+ # Add the moderation action if there is one.
+ if member.moderation_action is not None:
+ response['moderation_action'] = member.moderation_action
# Add the user link if there is one.
user = member.user
if user is not None:
diff --git a/src/mailman/rules/docs/moderation.rst b/src/mailman/rules/docs/moderation.rst
index f5ceec29a..56602189b 100644
--- a/src/mailman/rules/docs/moderation.rst
+++ b/src/mailman/rules/docs/moderation.rst
@@ -2,9 +2,10 @@
Moderation
==========
-All members and nonmembers have a moderation action. When the action is not
-`defer`, the `moderation` rule flags the message as needing moderation. This
-might be to automatically accept, discard, reject, or hold the message.
+All members and nonmembers have a moderation action, which defaults to the
+list's default action. When the action is not `defer`, the `moderation` rule
+flags the message as needing moderation. This might be to automatically
+accept, discard, reject, or hold the message.
Two separate rules check for member and nonmember moderation. Member
moderation happens early in the built-in chain, while nonmember moderation
@@ -30,7 +31,7 @@ postings are not moderated.
as MemberRole.member>
>>> member = mlist.members.get_member('aperson@example.com')
- >>> print(member.moderation_action)
+ >>> print(mlist.default_member_action)
Action.defer
Because Anne is not moderated, the member moderation rule does not match.
@@ -44,9 +45,9 @@ Because Anne is not moderated, the member moderation rule does not match.
>>> member_rule.check(mlist, member_msg, {})
False
-Once the member's moderation action is set to something other than `defer`,
-the rule matches. Also, the message metadata has a few extra pieces of
-information for the eventual moderation chain.
+Once the member's moderation action is set to something other than `defer` or
+``None``, the rule matches. Also, the message metadata has a few extra pieces
+of information for the eventual moderation chain.
>>> from mailman.interfaces.action import Action
>>> member.moderation_action = Action.hold
@@ -78,7 +79,7 @@ Bart, who is not a member of the mailing list, sends a message to the list.
as MemberRole.nonmember>
>>> nonmember = mlist.nonmembers.get_member('bperson@example.com')
- >>> print(nonmember.moderation_action)
+ >>> print(mlist.default_nonmember_action)
Action.hold
When Bart is registered as a nonmember of the list, his moderation action is
diff --git a/src/mailman/rules/moderation.py b/src/mailman/rules/moderation.py
index fdecd1d5f..9c89cf0b2 100644
--- a/src/mailman/rules/moderation.py
+++ b/src/mailman/rules/moderation.py
@@ -42,8 +42,10 @@ class MemberModeration:
"""See `IRule`."""
for sender in msg.senders:
member = mlist.members.get_member(sender)
- action = (None if member is None
- else member.moderation_action)
+ if member is None:
+ return False
+ action = (member.moderation_action
+ or mlist.default_member_action)
if action is Action.defer:
# The regular moderation rules apply.
return False
@@ -112,7 +114,8 @@ class NonmemberModeration:
_record_action(msgdata, action, sender,
reason.format(action))
return True
- action = nonmember.moderation_action
+ action = (nonmember.moderation_action
+ or mlist.default_nonmember_action)
if action is Action.defer:
# The regular moderation rules apply.
return False
diff --git a/src/mailman/rules/tests/test_moderation.py b/src/mailman/rules/tests/test_moderation.py
index df1658792..3e80aeeb5 100644
--- a/src/mailman/rules/tests/test_moderation.py
+++ b/src/mailman/rules/tests/test_moderation.py
@@ -144,3 +144,60 @@ A message body.
self.assertEqual(
msgdata['moderation_action'], action_name,
'Wrong action for {}: {}'.format(address, action_name))
+
+ def test_nonmember_fallback_to_list_defaults(self):
+ # https://gitlab.com/mailman/mailman/issues/189
+ self._mlist.default_nonmember_action = Action.hold
+ user_manager = getUtility(IUserManager)
+ user_manager.create_address('anne@example.com')
+ rule = moderation.NonmemberModeration()
+ msg = mfs("""\
+From: anne@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ # First, the message should get held
+ msgdata = {}
+ result = rule.check(self._mlist, msg, msgdata)
+ self.assertTrue(result)
+ self.assertEqual(msgdata.get('moderation_action'), 'hold')
+ # Then the list's default nonmember action is changed
+ self._mlist.default_nonmember_action = Action.discard
+ msg.replace_header('Message-ID', '<ant2>')
+ # This time, the message should be discarded
+ result = rule.check(self._mlist, msg, msgdata)
+ self.assertTrue(result)
+ self.assertEqual(msgdata.get('moderation_action'), 'discard')
+
+ def test_member_fallback_to_list_defaults(self):
+ # https://gitlab.com/mailman/mailman/issues/189
+ self._mlist.default_member_action = Action.accept
+ user_manager = getUtility(IUserManager)
+ anne = user_manager.create_address('anne@example.com')
+ self._mlist.subscribe(anne, MemberRole.member)
+ rule = moderation.MemberModeration()
+ msg = mfs("""\
+From: anne@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ # First, the message should get held
+ msgdata = {}
+ result = rule.check(self._mlist, msg, msgdata)
+ self.assertTrue(result)
+ self.assertEqual(msgdata.get('moderation_action'), 'accept')
+ # Then the list's default nonmember action is changed
+ self._mlist.default_member_action = Action.hold
+ msg.replace_header('Message-ID', '<ant2>')
+ # This time, the message should be discarded
+ result = rule.check(self._mlist, msg, msgdata)
+ self.assertTrue(result)
+ self.assertEqual(msgdata.get('moderation_action'), 'hold')
diff --git a/src/mailman/utilities/importer.py b/src/mailman/utilities/importer.py
index 9a5684d9c..da19613d8 100644
--- a/src/mailman/utilities/importer.py
+++ b/src/mailman/utilities/importer.py
@@ -576,8 +576,6 @@ def import_roster(mlist, config_dict, members, role, action=None):
# option to know which action should be taken.
action = member_moderation_action_mapping(
config_dict.get("member_moderation_action"))
- else:
- action = Action.accept
if action is not None:
# Either this was set right above or in the function's arguments
# for nonmembers.
diff --git a/src/mailman/utilities/tests/test_import.py b/src/mailman/utilities/tests/test_import.py
index 637f78585..83161bf1f 100644
--- a/src/mailman/utilities/tests/test_import.py
+++ b/src/mailman/utilities/tests/test_import.py
@@ -1112,9 +1112,10 @@ class TestPreferencesImport(unittest.TestCase):
self._do_test(128, dict(moderation_action=Action.discard))
def test_no_moderate(self):
- # If option flag Moderate is not set, action is accept
+ # If option flag Moderate is not set, action is None (fallback to the
+ # mailing list's action).
self._pckdict['member_moderation_action'] = 1 # reject
- self._do_test(0, dict(moderation_action=Action.accept))
+ self._do_test(0, dict(moderation_action=None))
def test_multiple_options(self):
# DontReceiveDuplicates & DisableMime & SuppressPasswordReminder