Barry Warsaw pushed to branch master at mailman / Mailman

Commits:
5a6344a8 by Aurélien Bompard at 2016-01-13T19:36:29-05:00
Allow fuzz search for members in SubscriptionService

- - - - -
bbe2a437 by Aurélien Bompard at 2016-01-13T19:36:29-05:00
Member search can be done using GET requests

- - - - -
a4ebbd16 by Barry Warsaw at 2016-01-13T19:49:16-05:00
Add NEWS and tweak.

- - - - -


6 changed files:

- src/mailman/docs/NEWS.rst
- src/mailman/interfaces/subscriptions.py
- src/mailman/model/docs/subscriptions.rst
- src/mailman/model/subscriptions.py
- src/mailman/rest/docs/membership.rst
- src/mailman/rest/members.py


Changes:

=====================================
src/mailman/docs/NEWS.rst
=====================================
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -79,6 +79,8 @@ Interfaces
    same algorithm.  (Closes #118)
  * ``IMessageStore.delete_message()`` no longer raises a ``LookupError`` when
    you attempt to delete a nonexistent message from the message store.
+ * ``ISubscriptionService.find_members()`` accepts asterisks as wildcards in
+   the ``subscriber`` argument string.  Given by Aurélien Bompard.
 
 Internal API
 ------------
@@ -133,6 +135,8 @@ REST
    given action.
  * Global and list-centric bans can now be managed through the REST API.
    Given by Aurélien Bompard.
+ * ``<api>/members/find`` accepts GET query parameters in addition to POST
+   arguments.  Given by Aurélien Bompard.
 
 Other
 -----


=====================================
src/mailman/interfaces/subscriptions.py
=====================================
--- a/src/mailman/interfaces/subscriptions.py
+++ b/src/mailman/interfaces/subscriptions.py
@@ -110,7 +110,8 @@ class ISubscriptionService(Interface):
         list.
 
         :param subscriber: The email address or user id of the user getting
-            subscribed.
+            subscribed.  This argument may contain asterisks, which will be
+            interpreted as wildcards in the search pattern.
         :type subscriber: string or int
         :param list_id: The list id of the mailing list to search for the
             subscriber's memberships on.


=====================================
src/mailman/model/docs/subscriptions.rst
=====================================
--- a/src/mailman/model/docs/subscriptions.rst
+++ b/src/mailman/model/docs/subscriptions.rst
@@ -105,6 +105,22 @@ There may be no matching memberships.
     >>> list(service.find_members('d...@example.com'))
     []
 
+The address may contain asterisks, which will be interpreted as a wildcard in
+the search pattern.
+
+    >>> for member in service.find_members('*person*'):
+    ...     print(member)
+    <Member: Anne Person <aper...@example.com>
+        on a...@example.com as MemberRole.member>
+    <Member: Anne Person <aper...@example.com>
+        on a...@example.com as MemberRole.owner>
+    <Member: Bart Person <bper...@example.com>
+        on a...@example.com as MemberRole.moderator>
+    <Member: Bart Person <bper...@example.com>
+        on b...@example.com as MemberRole.owner>
+    <Member: Cris Person <cper...@example.com>
+        on c...@example.com as MemberRole.member>
+
 Memberships can also be searched for by user id.
 
     >>> for member in service.find_members(anne_1.user.user_id):


=====================================
src/mailman/model/subscriptions.py
=====================================
--- a/src/mailman/model/subscriptions.py
+++ b/src/mailman/model/subscriptions.py
@@ -94,10 +94,18 @@ class SubscriptionService:
         if subscriber is not None:
             if isinstance(subscriber, str):
                 # subscriber is an email address.
-                q_address = q_address.filter(
-                    Address.email == subscriber.lower())
-                q_user = q_user.join(User.addresses).filter(
-                    Address.email == subscriber.lower())
+                subscriber = subscriber.lower()
+                if '*' in subscriber:
+                    subscriber = subscriber.replace('*', '%')
+                    q_address = q_address.filter(
+                        Address.email.like(subscriber))
+                    q_user = q_user.join(User.addresses).filter(
+                        Address.email.like(subscriber))
+                else:
+                    q_address = q_address.filter(
+                        Address.email == subscriber)
+                    q_user = q_user.join(User.addresses).filter(
+                        Address.email == subscriber)
             else:
                 # subscriber is a user id.
                 q_address = q_address.join(Address.user).filter(


=====================================
src/mailman/rest/docs/membership.rst
=====================================
--- a/src/mailman/rest/docs/membership.rst
+++ b/src/mailman/rest/docs/membership.rst
@@ -626,6 +626,28 @@ Finally, we can search for a specific member given all 
three criteria.
     start: 0
     total_size: 1
 
+Search can also be performed using HTTP GET queries.
+
+    >>> dump_json('http://localhost:9001/3.0/members/find'
+    ...           '?subscriber=cper...@example.com'
+    ...           '&list_id=bee.example.com'
+    ...           '&role=member'
+    ...           )
+    entry 0:
+        address: http://localhost:9001/3.0/addresses/cper...@example.com
+        delivery_mode: regular
+        email: cper...@example.com
+        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
+    http_etag: ...
+    start: 0
+    total_size: 1
+
 
 Joining a mailing list
 ======================


=====================================
src/mailman/rest/members.py
=====================================
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -356,19 +356,32 @@ class _FoundMembers(MemberCollection):
 class FindMembers(_MemberBase):
     """/members/find"""
 
+    def on_get(self, request, response):
+        return self._find(request, response)
+
     def on_post(self, request, response):
+        return self._find(request, response)
+
+    def _find(self, request, response):
         """Find a member"""
         service = getUtility(ISubscriptionService)
         validator = Validator(
             list_id=str,
             subscriber=str,
             role=enum_validator(MemberRole),
-            _optional=('list_id', 'subscriber', 'role'))
+            # Allow pagination.
+            page=int,
+            count=int,
+            _optional=('list_id', 'subscriber', 'role', 'page', 'count'))
         try:
             data = validator(request)
         except ValueError as error:
             bad_request(response, str(error))
         else:
+            # Remove any optional pagination query elements; they will be
+            # handled later.
+            data.pop('page', None)
+            data.pop('count', None)
             members = service.find_members(**data)
             resource = _FoundMembers(members, self.api)
             okay(response, etag(resource._make_collection(request)))



View it on GitLab: 
https://gitlab.com/mailman/mailman/compare/95446742669349777ee4101237a76395f1dfaa87...a4ebbd164bdba4a7ede651dfcf802c300e8e9743
_______________________________________________
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to