summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/docs/NEWS.rst2
-rw-r--r--src/mailman/rest/docs/listconf.rst4
-rw-r--r--src/mailman/rest/helpers.py12
-rw-r--r--src/mailman/rest/listconf.py7
-rw-r--r--src/mailman/rest/tests/test_listconf.py2
5 files changed, 26 insertions, 1 deletions
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index bc649104b..f0a0efb0d 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -209,6 +209,8 @@ REST
* A member's ``moderation_action`` can be reset, allowing fallback to the
list's ``default_member_action`` by setting the attribute to the empty
string in the REST API. Given by Aurélien Bompard.
+ * A list's ``moderator_password`` can be set via the REST API. Given by
+ Andrew Breksa. (Closes #207)
Other
-----
diff --git a/src/mailman/rest/docs/listconf.rst b/src/mailman/rest/docs/listconf.rst
index e8d463007..6804644ac 100644
--- a/src/mailman/rest/docs/listconf.rst
+++ b/src/mailman/rest/docs/listconf.rst
@@ -53,6 +53,7 @@ All readable attributes for a list are available on a sub-resource.
leave_address: ant-leave@example.com
list_name: ant
mail_host: example.com
+ moderator_password: None
next_digest_number: 1
no_reply_address: noreply@example.com
owner_address: ant-owner@example.com
@@ -119,6 +120,7 @@ When using ``PUT``, all writable attributes must be included.
... welcome_message_uri='mailman:///welcome.txt',
... default_member_action='hold',
... default_nonmember_action='discard',
+ ... moderator_password='password',
... ),
... 'PUT')
content-length: 0
@@ -165,6 +167,8 @@ These values are changed permanently.
...
include_rfc2369_headers: False
...
+ moderator_password: {plaintext}password
+ ...
posting_pipeline: virgin
reply_goes_to_list: point_to_list
reply_to_address: bee@example.com
diff --git a/src/mailman/rest/helpers.py b/src/mailman/rest/helpers.py
index 34fff3ba3..9ab1f434e 100644
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -21,6 +21,7 @@ import json
import falcon
import hashlib
+from contextlib import suppress
from datetime import datetime, timedelta
from enum import Enum
from lazr.config import as_boolean
@@ -46,9 +47,20 @@ class ExtendedEncoder(json.JSONEncoder):
# It's up to the decoding validator to associate this name with
# the right Enum class.
return obj.name
+ elif isinstance(obj, bytes):
+ return bytes_to_str(obj)
return super().default(obj)
+def bytes_to_str(value):
+ # Convert a string to unicode when the encoding is not declared.
+ if not isinstance(value, bytes):
+ return value
+ for encoding in ('ascii', 'utf-8', 'raw_unicode_escape'):
+ with suppress(UnicodeDecodeError):
+ return value.decode(encoding)
+
+
@public
def etag(resource):
"""Calculate the etag and return a JSON representation.
diff --git a/src/mailman/rest/listconf.py b/src/mailman/rest/listconf.py
index 65ce8c5f7..3294ba8b6 100644
--- a/src/mailman/rest/listconf.py
+++ b/src/mailman/rest/listconf.py
@@ -68,6 +68,12 @@ def pipeline_validator(pipeline_name):
raise ValueError('Unknown pipeline: {}'.format(pipeline_name))
+def password_bytes_validator(value):
+ if value is None or isinstance(value, bytes):
+ return value
+ return config.password_context.encrypt(value).encode('utf-8')
+
+
# This is the list of IMailingList attributes that are exposed through the
# REST API. The values of the keys are the GetterSetter instance holding the
# decoder used to convert the web request string to an internally valid value.
@@ -120,6 +126,7 @@ ATTRIBUTES = dict(
last_post_at=GetterSetter(None),
leave_address=GetterSetter(None),
list_name=GetterSetter(None),
+ moderator_password=GetterSetter(password_bytes_validator),
next_digest_number=GetterSetter(None),
no_reply_address=GetterSetter(None),
owner_address=GetterSetter(None),
diff --git a/src/mailman/rest/tests/test_listconf.py b/src/mailman/rest/tests/test_listconf.py
index eb39d7dea..b5d8c49f6 100644
--- a/src/mailman/rest/tests/test_listconf.py
+++ b/src/mailman/rest/tests/test_listconf.py
@@ -28,7 +28,6 @@ from mailman.testing.helpers import call_api
from mailman.testing.layers import RESTLayer
from urllib.error import HTTPError
-
# The representation of the listconf resource as a dictionary. This is used
# when PUTting to the list's configuration resource.
RESOURCE = dict(
@@ -65,6 +64,7 @@ RESOURCE = dict(
first_strip_reply_to=True,
goodbye_message_uri='mailman:///goodbye.txt',
include_rfc2369_headers=False,
+ moderator_password='password',
posting_pipeline='virgin',
reply_goes_to_list='point_to_list',
reply_to_address='bee@example.com',