Jimmy Bergman has proposed merging 
lp:~jimmy-sigint/mailman/rest_api_ban_management into lp:mailman.

Requested reviews:
  Mailman Coders (mailman-coders)

For more details, see:
https://code.launchpad.net/~jimmy-sigint/mailman/rest_api_ban_management/+merge/125648

This branch adds a REST API resource for managing per list bans, which is useful
in control panels targetting mailman 3.

See the src/mailman/rest/docs/membership.rst patch for usage.
-- 
https://code.launchpad.net/~jimmy-sigint/mailman/rest_api_ban_management/+merge/125648
Your team Mailman Coders is requested to review the proposed merge of 
lp:~jimmy-sigint/mailman/rest_api_ban_management into lp:mailman.
=== modified file 'src/mailman/interfaces/bans.py'
--- src/mailman/interfaces/bans.py	2012-01-01 19:14:46 +0000
+++ src/mailman/interfaces/bans.py	2012-09-21 09:06:20 +0000
@@ -108,3 +108,13 @@
             or not.
         :rtype: bool
         """
+
+    def ban_list(mailing_list):
+        """Retrieves a list of bans for a specific mailing list.
+
+        :param mailing_list: The fqdn name of the mailing list to retrieve
+            the ban list for.
+        :type mailing_list: string
+        :return: A list of banned emails.
+        :rtype: list
+        """

=== modified file 'src/mailman/model/bans.py'
--- src/mailman/model/bans.py	2012-04-26 02:08:22 +0000
+++ src/mailman/model/bans.py	2012-09-21 09:06:20 +0000
@@ -109,3 +109,8 @@
                     re.match(ban.email, email, re.IGNORECASE) is not None):
                     return True
         return False
+
+    @dbconnection
+    def ban_list(self, store, mailing_list):
+        """See `IBanManager`."""
+        return [ ban.email for ban in store.find(Ban, mailing_list=mailing_list) ]

=== modified file 'src/mailman/rest/docs/membership.rst'
--- src/mailman/rest/docs/membership.rst	2012-09-05 01:31:50 +0000
+++ src/mailman/rest/docs/membership.rst	2012-09-21 09:06:20 +0000
@@ -597,6 +597,51 @@
     >>> set(member.mailing_list for member in elly.memberships.members)
     set([])
 
+Handling the list of banned addresses
+=====================================
+
+To ban an address from subscribing you can POST to the /banlist child
+of any list using the REST API.
+::
+
+    # Ensure our previous reads don't keep the database lock.
+    >>> transaction.abort()
+    >>> dump_json('http://localhost:9001/3.0/lists/[email protected]'
+    ...           '/banlist', { 'address': '[email protected]' })
+    content-length: 0
+    ...
+    status: 201
+
+This address is now banned, and you can get the list of banned addresses using
+the REST API:
+
+    # Ensure our previous reads don't keep the database lock.
+    >>> transaction.abort()
+    >>> dump_json('http://localhost:9001/3.0/lists/[email protected]/banlist')
+    entry 0:
+        banned_email: [email protected]
+    ...
+
+Or checking if a single address is banned:
+
+    >>> dump_json('http://localhost:9001/3.0/lists/[email protected]/banlist/[email protected]')
+    banned_email: [email protected]
+    http_etag: ...
+
+Unbanning addresses is also possible using the REST API.
+
+    >>> dump_json('http://localhost:9001/3.0/lists/[email protected]/banlist'
+    ...           '/[email protected]', method='DELETE')
+    content-length: 0
+    ...
+    status: 200
+
+After unbanning it shouldn't be available in the ban list:
+
+    >>> dump_json('http://localhost:9001/3.0/lists/[email protected]/banlist/[email protected]')
+    Traceback (most recent call last):
+    ...
+    HTTPError: HTTP Error 404: 404 Not Found
 
 Digest delivery
 ===============

=== modified file 'src/mailman/rest/lists.py'
--- src/mailman/rest/lists.py	2012-09-05 01:31:50 +0000
+++ src/mailman/rest/lists.py	2012-09-21 09:06:20 +0000
@@ -23,6 +23,8 @@
 __all__ = [
     'AList',
     'AllLists',
+    'BannedAddress',
+    'BannedAddresses',
     'ListConfiguration',
     'ListsForDomain',
     ]
@@ -33,6 +35,7 @@
 from zope.component import getUtility
 
 from mailman.app.lifecycle import create_list, remove_list
+from mailman.interfaces.bans import IBanManager
 from mailman.interfaces.domain import BadDomainSpecificationError
 from mailman.interfaces.listmanager import (
     IListManager, ListAlreadyExistsError)
@@ -82,6 +85,30 @@
 
 
 @restish_matcher
+def banlist_matcher(request, segments):
+    """A matcher of all banned addresses for a mailing list.
+
+    e.g. /banlist
+    """
+    if len(segments) != 1 or segments[0] != 'banlist':
+        return None
+    else:
+        return (), {}, ()
+
+
+@restish_matcher
+def banned_matcher(request, segments):
+    """A matcher of a single banned addresses for a mailing list.
+
+    e.g. /banlist/[email protected]
+    """
+    if len(segments) != 2 or segments[0] != 'banlist':
+        return None
+    else:
+        return (), dict(address=segments[1]), ()
+
+
+@restish_matcher
 def config_matcher(request, segments):
     """A matcher for a mailing list's configuration resource.
 
@@ -173,6 +200,86 @@
             return http.not_found()
         return HeldMessages(self._mlist)
 
+    @resource.child(banlist_matcher)
+    def banlist(self, request, segments, attribute=None):
+        """Return a list of banned addresses."""
+        return BannedAddresses(self._mlist)
+
+    @resource.child(banned_matcher)
+    def banned(self, request, segments, address):
+        """Return a list of banned addresses."""
+        return BannedAddress(self._mlist, address)
+
+
+
+class BannedAddress(resource.Resource, CollectionMixin):
+    """Class to represent a banned address."""
+
+    def __init__(self, mlist, address):
+        self._mlist = mlist 
+        self._address = address
+        self.ban_manager = getUtility(IBanManager)
+
+    @resource.GET()
+    def container(self, request):
+        """/banlist/[email protected]"""
+        if self._mlist is None or self._address is None or not self.ban_manager.is_banned(self._address, self._mlist.fqdn_listname):
+            return http.not_found()
+        resource = dict(banned_email=self._address)
+        return http.ok([], etag(resource))
+
+    @resource.DELETE()
+    def remove(self, request):
+        """Remove an address from the ban list."""
+        if self._mlist is None or self._address is None:
+            return http.not_found()
+        else:
+            if not self.ban_manager.is_banned(self._address, self._mlist.fqdn_listname):
+                return http.bad_request([], b'Address is not in ban list')
+
+        self.ban_manager.unban(self._address, self._mlist.fqdn_listname)
+        return http.ok([], '')
+
+class BannedAddresses(resource.Resource, CollectionMixin):
+    """Class to represent the list of all banned addresses."""
+
+    def __init__(self, mlist):
+        self._mlist = mlist 
+        self.ban_manager = getUtility(IBanManager)
+
+    def _resource_as_dict(self, item):
+        """See `CollectionMixin`."""
+        return dict(
+            banned_email=item,
+            )
+
+    def _get_collection(self, request):
+        """See `CollectionMixin`."""
+        return self.ban_manager.ban_list(self._mlist.fqdn_listname)
+
+    @resource.GET()
+    def container(self, request):
+        """/banlist"""
+        resource = self._make_collection(request)
+        return http.ok([], etag(resource))
+
+    @resource.POST()
+    def create(self, request):
+        """Ban some address from subscribing."""
+        try:
+            validator = Validator(address=unicode)
+            converted = validator(request)
+
+            address = converted['address']
+            if self.ban_manager.is_banned(address, self._mlist.fqdn_listname):
+                return http.bad_request([], b'Address is already in ban list')
+
+            self.ban_manager.ban(address, self._mlist.fqdn_listname)
+        except ValueError as error:
+            return http.bad_request([], str(error))
+        location = path_to('lists/{0}/banlist'.format(self._mlist.fqdn_listname))
+        return http.created(location, [], None)
+
 
 
 class AllLists(_ListBase):

_______________________________________________
Mailman-coders mailing list
[email protected]
http://mail.python.org/mailman/listinfo/mailman-coders

Reply via email to