Barry Warsaw pushed to branch master at mailman / Mailman
Commits:
811f10df by Barry Warsaw at 2015-09-20T14:56:47Z
Document an attribute.
Add a doctest for the `owners` top-level resource.
- - - - -
b2a05024 by Barry Warsaw at 2015-09-20T14:56:47Z
Start of owners top level resource.
- - - - -
50757a93 by Barry Warsaw at 2015-09-20T15:43:28Z
Add server_owners attribute to the user manager.
- - - - -
77b8745f by Barry Warsaw at 2015-09-20T15:54:06Z
Implement the REST API for <api>/owners.
- - - - -
6060ae33 by Barry Warsaw at 2015-09-20T15:59:11Z
Add another code-path test.
- - - - -
4188b533 by Barry Warsaw at 2015-09-20T17:23:54Z
Add NEWS.
- - - - -
61877ba9 by Barry Warsaw at 2015-09-22T23:35:47Z
Document an attribute.
Add a doctest for the `owners` top-level resource.
- - - - -
8dfa62d6 by Barry Warsaw at 2015-09-22T23:35:47Z
Start of owners top level resource.
- - - - -
f27103bf by Barry Warsaw at 2015-09-22T23:35:47Z
Add server_owners attribute to the user manager.
- - - - -
3b90cb8e by Barry Warsaw at 2015-09-22T23:35:47Z
Implement the REST API for <api>/owners.
- - - - -
f6e09955 by Barry Warsaw at 2015-09-22T23:35:47Z
Add another code-path test.
- - - - -
2f6a9c1f by Barry Warsaw at 2015-09-22T23:35:47Z
Add NEWS.
- - - - -
d68b6a21 by Barry Warsaw at 2015-09-23T16:25:15Z
Merge branch 'issue135' of gitlab.com:warsaw/mailman into issue135
- - - - -
c8811695 by Barry Warsaw at 2015-09-23T16:27:20Z
Document an attribute.
Add a doctest for the `owners` top-level resource.
- - - - -
4f1fba02 by Barry Warsaw at 2015-09-23T16:27:20Z
Start of owners top level resource.
- - - - -
dfc1cff7 by Barry Warsaw at 2015-09-23T16:27:20Z
Add server_owners attribute to the user manager.
- - - - -
c8779a10 by Barry Warsaw at 2015-09-23T16:27:20Z
Implement the REST API for <api>/owners.
- - - - -
b0a9d9e3 by Barry Warsaw at 2015-09-23T16:27:20Z
Add another code-path test.
- - - - -
afb59427 by Barry Warsaw at 2015-09-23T16:27:20Z
Add NEWS.
- - - - -
3023f73c by Barry Warsaw at 2015-09-23T16:30:37Z
Merge branch 'issue135' of gitlab.com:warsaw/mailman into issue135
- - - - -
6c75191a by Barry Warsaw at 2015-09-23T20:45:41Z
A new top-level resource `<api>/owners` can be used to get the list of
server
owners as `IUser`s. (Closes #135)
- - - - -
9 changed files:
- src/mailman/docs/NEWS.rst
- src/mailman/interfaces/user.py
- src/mailman/interfaces/usermanager.py
- src/mailman/model/docs/usermanager.rst
- src/mailman/model/usermanager.py
- + src/mailman/rest/docs/owners.rst
- src/mailman/rest/root.py
- + src/mailman/rest/tests/test_owners.py
- src/mailman/rest/users.py
Changes:
=====================================
src/mailman/docs/NEWS.rst
=====================================
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -78,6 +78,8 @@ REST
Bompard.
* The REST API incorrectly parsed `is_server_owner` values when given
explicitly in the POST that creates a user. (Closes #136)
+ * A new top-level resource `<api>/owners` can be used to get the list of
+ server owners as `IUser`s. (Closes #135)
* By POSTing to a user resource with an existing unlinked address, you can
link the address to the user. Given by Abhilash Raj.
=====================================
src/mailman/interfaces/user.py
=====================================
--- a/src/mailman/interfaces/user.py
+++ b/src/mailman/interfaces/user.py
@@ -70,6 +70,9 @@ class IUser(Interface):
memberships = Attribute(
"""A roster of this user's memberships.""")
+ is_server_owner = Attribute(
+ """Boolean flag indicating whether the user is a server owner.""")
+
def register(email, display_name=None):
"""Register the given email address and link it to this user.
=====================================
src/mailman/interfaces/usermanager.py
=====================================
--- a/src/mailman/interfaces/usermanager.py
+++ b/src/mailman/interfaces/usermanager.py
@@ -126,3 +126,6 @@ class IUserManager(Interface):
members = Attribute(
"""An iterator of all the `IMembers` in the database.""")
+
+ server_owners = Attribute(
+ """An iterator over all the `IUsers` who are server owners.""")
=====================================
src/mailman/model/docs/usermanager.rst
=====================================
--- a/src/mailman/model/docs/usermanager.rst
+++ b/src/mailman/model/docs/usermanager.rst
@@ -201,3 +201,47 @@ The user has a single unverified address object.
>>> for address in cris.addresses:
... print(repr(address))
<Address: Cris Person <[email protected]> [not verified] at ...>
+
+
+Server owners
+=============
+
+Some users are designated as *server owners*. At first there are no server
+owners.
+
+ >>> len(list(user_manager.server_owners))
+ 0
+
+Dan is made a server owner.
+
+ >>> user_4.is_server_owner = True
+ >>> owners = list(user_manager.server_owners)
+ >>> len(owners)
+ 1
+ >>> owners[0]
+ <User "Dan Person" (...) at ...>
+
+Now Ben and Claire are also made server owners.
+
+ >>> user_2.is_server_owner = True
+ >>> user_3.is_server_owner = True
+ >>> owners = list(user_manager.server_owners)
+ >>> len(owners)
+ 3
+ >>> from operator import attrgetter
+ >>> for user in sorted(owners, key=attrgetter('display_name')):
+ ... print(user)
+ <User "Ben Person" (...) at ...>
+ <User "Claire Person" (...) at ...>
+ <User "Dan Person" (...) at ...>
+
+Clair retires as a server owner.
+
+ >>> user_3.is_server_owner = False
+ >>> owners = list(user_manager.server_owners)
+ >>> len(owners)
+ 2
+ >>> for user in sorted(owners, key=attrgetter('display_name')):
+ ... print(user)
+ <User "Ben Person" (...) at ...>
+ <User "Dan Person" (...) at ...>
=====================================
src/mailman/model/usermanager.py
=====================================
--- a/src/mailman/model/usermanager.py
+++ b/src/mailman/model/usermanager.py
@@ -141,4 +141,11 @@ class UserManager:
def members(self, store):
"""See `IUserManager."""
for member in store.query(Member).all():
- yield member
+ yield member
+
+ @property
+ @dbconnection
+ def server_owners(self, store):
+ """ See `IUserManager."""
+ users = store.query(User).filter_by(is_server_owner=True)
+ yield from users
=====================================
src/mailman/rest/docs/owners.rst
=====================================
--- /dev/null
+++ b/src/mailman/rest/docs/owners.rst
@@ -0,0 +1,89 @@
+===============
+ Server owners
+===============
+
+Certain users can be designated as *server owners*. This role has no direct
+function in the core, but it can be used by clients of the REST API to
+determine additional permissions. For example, Postorius might allow server
+owners to create new domains.
+
+Initially, there are no server owners.
+
+ >>> dump_json('http://localhost:9001/3.0/owners')
+ http_etag: "..."
+ start: 0
+ total_size: 0
+
+When new users are created in the core, they do not become server owners by
+default.
+
+ >>> from zope.component import getUtility
+ >>> from mailman.interfaces.usermanager import IUserManager
+ >>> user_manager = getUtility(IUserManager)
+ >>> anne = user_manager.create_user('[email protected]', 'Anne Person')
+ >>> transaction.commit()
+ >>> dump_json('http://localhost:9001/3.0/owners')
+ http_etag: "..."
+ start: 0
+ total_size: 0
+
+Anne's server owner flag is set.
+
+ >>> anne.is_server_owner = True
+ >>> transaction.commit()
+
+And now we can find her user record.
+
+ >>> dump_json('http://localhost:9001/3.0/owners')
+ entry 0:
+ created_on: 2005-08-01T07:49:23
+ display_name: Anne Person
+ http_etag: "..."
+ is_server_owner: True
+ self_link: http://localhost:9001/3.0/users/1
+ user_id: 1
+ http_etag: "..."
+ start: 0
+ total_size: 1
+
+Bart and Cate are also users, but not server owners.
+
+ >>> bart = user_manager.create_user('[email protected]', 'Bart Person')
+ >>> cate = user_manager.create_user('[email protected]', 'Cate Person')
+ >>> transaction.commit()
+ >>> dump_json('http://localhost:9001/3.0/owners')
+ entry 0:
+ created_on: 2005-08-01T07:49:23
+ display_name: Anne Person
+ http_etag: "..."
+ is_server_owner: True
+ self_link: http://localhost:9001/3.0/users/1
+ user_id: 1
+ http_etag: "..."
+ start: 0
+ total_size: 1
+
+Anne retires as a server owner, with Bart and Cate taking over.
+
+ >>> anne.is_server_owner = False
+ >>> bart.is_server_owner = True
+ >>> cate.is_server_owner = True
+ >>> transaction.commit()
+ >>> dump_json('http://localhost:9001/3.0/owners')
+ entry 0:
+ created_on: 2005-08-01T07:49:23
+ display_name: Bart Person
+ http_etag: "..."
+ is_server_owner: True
+ self_link: http://localhost:9001/3.0/users/2
+ user_id: 2
+ entry 1:
+ created_on: 2005-08-01T07:49:23
+ display_name: Cate Person
+ http_etag: "..."
+ is_server_owner: True
+ self_link: http://localhost:9001/3.0/users/3
+ user_id: 3
+ http_etag: "..."
+ start: 0
+ total_size: 2
=====================================
src/mailman/rest/root.py
=====================================
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -39,7 +39,7 @@ from mailman.rest.members import AMember, AllMembers,
FindMembers
from mailman.rest.preferences import ReadOnlyPreferences
from mailman.rest.queues import AQueue, AQueueFile, AllQueues
from mailman.rest.templates import TemplateFinder
-from mailman.rest.users import AUser, AllUsers
+from mailman.rest.users import AUser, AllUsers, ServerOwners
from zope.component import getUtility
@@ -234,6 +234,14 @@ class TopLevel:
return AUser(user_id), segments
@child()
+ def owners(self, request, segments):
+ """/<api>/owners"""
+ if len(segments) != 0:
+ return BadRequest(), []
+ else:
+ return ServerOwners(), segments
+
+ @child()
def templates(self, request, segments):
"""/<api>/templates/<fqdn_listname>/<template>/[<language>]
=====================================
src/mailman/rest/tests/test_owners.py
=====================================
--- /dev/null
+++ b/src/mailman/rest/tests/test_owners.py
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Additional tests for the top-level owners resource."""
+
+__all__ = [
+ 'TestOwners',
+ ]
+
+
+import unittest
+
+from mailman.testing.helpers import call_api
+from mailman.testing.layers import RESTLayer
+from urllib.error import HTTPError
+
+
+
+class TestOwners(unittest.TestCase):
+ layer = RESTLayer
+
+ def test_bogus_trailing_path(self):
+ # Nothing is allowed after the top-level /owners resource.
+ with self.assertRaises(HTTPError) as cm:
+ call_api('http://localhost:9001/3.0/owners/anne')
+ self.assertEqual(cm.exception.code, 400)
=====================================
src/mailman/rest/users.py
=====================================
--- a/src/mailman/rest/users.py
+++ b/src/mailman/rest/users.py
@@ -464,3 +464,18 @@ class OwnersForDomain(_UserBase):
def _get_collection(self, request):
"""See `CollectionMixin`."""
return list(self._domain.owners)
+
+
+
+class ServerOwners(_UserBase):
+ """All server owners."""
+
+ def on_get(self, request, response):
+ """/owners"""
+ resource = self._make_collection(request)
+ okay(response, etag(resource))
+
+ @paginate
+ def _get_collection(self, request):
+ """See `CollectionMixin`."""
+ return list(getUtility(IUserManager).server_owners)
View it on GitLab:
https://gitlab.com/mailman/mailman/compare/4e92faced9c8b215420971164fd5e1de97db7a46...6c75191a230474d51505ba3269f14b9093b35863
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org