summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurélien Bompard2015-11-30 13:59:37 +0100
committerBarry Warsaw2015-12-08 10:20:22 -0500
commit9c9d0f01f8f5dff5ec5a83b953be81edf81566be (patch)
treea4a16dd54e5b9f6e541d2f3c15335dbd66ae242f
parent054b412ad200924e2c7642b63ab4f300efc27b3b (diff)
downloadmailman-9c9d0f01f8f5dff5ec5a83b953be81edf81566be.tar.gz
mailman-9c9d0f01f8f5dff5ec5a83b953be81edf81566be.tar.zst
mailman-9c9d0f01f8f5dff5ec5a83b953be81edf81566be.zip
-rw-r--r--src/mailman/docs/NEWS.rst2
-rw-r--r--src/mailman/rest/docs/addresses.rst5
-rw-r--r--src/mailman/rest/docs/membership.rst71
-rw-r--r--src/mailman/rest/members.py16
-rw-r--r--src/mailman/rest/tests/test_membership.py13
5 files changed, 102 insertions, 5 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index 2ea0002cf..e76e68719 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -113,6 +113,8 @@ REST
* JSON representations for held message now include a ``self_link``.
* When ``[devmode]enabled`` is set, the JSON output is sorted. Given by
Aurélien Bompard.
+ * A member's moderation action can be changed via the REST API. Given by
+ Aurélien Bompard.
Other
-----
diff --git a/src/mailman/rest/docs/addresses.rst b/src/mailman/rest/docs/addresses.rst
index f70b64a39..6fbe84972 100644
--- a/src/mailman/rest/docs/addresses.rst
+++ b/src/mailman/rest/docs/addresses.rst
@@ -379,6 +379,7 @@ 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
@@ -389,6 +390,7 @@ 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
@@ -420,6 +422,7 @@ 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
@@ -430,6 +433,7 @@ 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
@@ -446,6 +450,7 @@ 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 c0f767179..20444f969 100644
--- a/src/mailman/rest/docs/membership.rst
+++ b/src/mailman/rest/docs/membership.rst
@@ -50,6 +50,7 @@ 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
@@ -66,6 +67,7 @@ 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
@@ -86,6 +88,7 @@ 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
@@ -96,6 +99,7 @@ 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
@@ -119,6 +123,7 @@ 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
@@ -129,6 +134,7 @@ 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
@@ -139,6 +145,7 @@ 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
@@ -168,6 +175,7 @@ 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
@@ -178,6 +186,7 @@ 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
@@ -188,6 +197,7 @@ 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
@@ -198,6 +208,7 @@ 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
@@ -208,6 +219,7 @@ 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
@@ -226,6 +238,7 @@ 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
@@ -236,6 +249,7 @@ 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
@@ -262,6 +276,7 @@ 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
@@ -280,6 +295,7 @@ 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
@@ -326,6 +342,7 @@ mailing list.
http_etag: ...
list_id: ant.example.com
member_id: 6
+ moderation_action: accept
role: moderator
self_link: http://localhost:9001/3.0/members/6
user: http://localhost:9001/3.0/users/4
@@ -336,6 +353,7 @@ 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
@@ -346,6 +364,7 @@ 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
@@ -356,6 +375,7 @@ mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 7
+ moderation_action: accept
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -366,6 +386,7 @@ 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
@@ -376,6 +397,7 @@ 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
@@ -386,6 +408,7 @@ 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
@@ -404,6 +427,7 @@ We can access all the owners of a list.
http_etag: ...
list_id: bee.example.com
member_id: 7
+ moderation_action: accept
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -425,6 +449,7 @@ A specific member can always be referenced by their role and address.
http_etag: ...
list_id: bee.example.com
member_id: 7
+ moderation_action: accept
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -442,6 +467,7 @@ 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
@@ -452,6 +478,7 @@ 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
@@ -471,6 +498,7 @@ 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
@@ -481,6 +509,7 @@ 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
@@ -491,6 +520,7 @@ 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
@@ -501,6 +531,7 @@ Or, we can find all the memberships for a particular mailing list.
http_etag: ...
list_id: bee.example.com
member_id: 7
+ moderation_action: accept
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -522,6 +553,7 @@ 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
@@ -532,6 +564,7 @@ list.
http_etag: ...
list_id: bee.example.com
member_id: 7
+ moderation_action: accept
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -552,6 +585,7 @@ 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
@@ -562,6 +596,7 @@ 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
@@ -583,6 +618,7 @@ 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
@@ -636,6 +672,7 @@ 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
@@ -682,6 +719,7 @@ 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
@@ -707,6 +745,7 @@ 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
@@ -774,6 +813,7 @@ 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
@@ -785,6 +825,7 @@ 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
@@ -843,6 +884,7 @@ 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
@@ -853,9 +895,38 @@ 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
http_etag: "..."
start: 0
total_size: 2
+
+
+Moderating a member
+===================
+
+The moderation action for a member can be changed by PATCH'ing the
+`moderation_action` attribute.
+::
+
+ >>> dump_json('http://localhost:9001/3.0/members/10')
+ address: http://localhost:9001/3.0/addresses/hperson@example.com
+ ...
+ moderation_action: defer
+ ...
+
+ >>> dump_json('http://localhost:9001/3.0/members/10', {
+ ... 'moderation_action': 'hold',
+ ... }, method='PATCH')
+ content-length: 0
+ date: ...
+ server: ...
+ status: 204
+
+ >>> dump_json('http://localhost:9001/3.0/members/10')
+ address: http://localhost:9001/3.0/addresses/hperson@example.com
+ ...
+ moderation_action: hold
+ ...
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index 6e72339db..88fa352a3 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -26,6 +26,7 @@ __all__ = [
from mailman.app.membership import add_member, delete_member
+from mailman.interfaces.action import Action
from mailman.interfaces.address import IAddress, InvalidEmailAddressError
from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.member import (
@@ -62,13 +63,14 @@ class _MemberBase(CollectionMixin):
# URL.
member_id = member.member_id.int
response = dict(
- list_id=member.list_id,
- email=member.address.email,
- role=role,
address=self.path_to('addresses/{}'.format(member.address.email)),
- self_link=self.path_to('members/{}'.format(member_id)),
delivery_mode=member.delivery_mode,
+ email=member.address.email,
+ list_id=member.list_id,
member_id=member_id,
+ moderation_action=member.moderation_action,
+ role=role,
+ self_link=self.path_to('members/{}'.format(member_id)),
)
# Add the user link if there is one.
user = member.user
@@ -178,7 +180,9 @@ class AMember(_MemberBase):
values = Validator(
address=str,
delivery_mode=enum_validator(DeliveryMode),
- _optional=('address', 'delivery_mode'))(request)
+ moderation_action=enum_validator(Action),
+ _optional=('address', 'delivery_mode', 'moderation_action'),
+ )(request)
except ValueError as error:
bad_request(response, str(error))
return
@@ -195,6 +199,8 @@ class AMember(_MemberBase):
return
if 'delivery_mode' in values:
self._member.preferences.delivery_mode = values['delivery_mode']
+ if 'moderation_action' in values:
+ self._member.moderation_action = values['moderation_action']
no_content(response)
diff --git a/src/mailman/rest/tests/test_membership.py b/src/mailman/rest/tests/test_membership.py
index 4542677b6..a3f7646c2 100644
--- a/src/mailman/rest/tests/test_membership.py
+++ b/src/mailman/rest/tests/test_membership.py
@@ -253,6 +253,19 @@ class TestMembership(unittest.TestCase):
call_api('http://localhost:9001/3.0/members/1/all')
self.assertEqual(cm.exception.code, 404)
+ def test_patch_member_invalid_moderation_action(self):
+ # /members/<id> PATCH with invalid 'moderation_action' returns 400.
+ with transaction():
+ anne = self._usermanager.create_address('anne@example.com')
+ self._mlist.subscribe(anne)
+ with self.assertRaises(HTTPError) as cm:
+ call_api('http://localhost:9001/3.0/members/1', {
+ 'moderation_action': 'invalid',
+ }, method='PATCH')
+ self.assertEqual(cm.exception.code, 400)
+ self.assertEqual(cm.exception.reason,
+ b'Cannot convert parameters: moderation_action')
+
class CustomLayer(ConfigLayer):