Merge lp:~postfuturist/mailman/rest-api-mods_owners into lp:mailman

Proposed by Stephen A. Goss
Status: Merged
Approved by: Barry Warsaw
Approved revision: 7043
Merged at revision: 7043
Proposed branch: lp:~postfuturist/mailman/rest-api-mods_owners
Merge into: lp:mailman
Diff against target: 201 lines (+50/-21)
6 files modified
src/mailman/app/membership.py (+4/-6)
src/mailman/app/subscriptions.py (+7/-10)
src/mailman/app/tests/test_membership.py (+13/-1)
src/mailman/interfaces/subscriptions.py (+3/-1)
src/mailman/rest/docs/membership.rst (+21/-2)
src/mailman/rest/members.py (+2/-1)
To merge this branch: bzr merge lp:~postfuturist/mailman/rest-api-mods_owners
Reviewer Review Type Date Requested Status
Barry Warsaw Approve
Review via email: mp+72977@code.launchpad.net

Description of the change

Added ability to add moderators and owners through existing REST API endpoints. Tests were updated as well.

To post a comment you must log in.
Revision history for this message
Stephen A. Goss (postfuturist) wrote :

The AlreadySubscribedError I removed is superfluous, as that error will get raised regardless in the call to `subscribe` if that is the case.

Revision history for this message
Barry Warsaw (barry) wrote :

Thanks for the code! It looks pretty good in general. I'm going to make a few stylistic fixes (indentation, parameter order, multiline import formatting), and I'll add a few more "bad path" tests to ensure the exception still gets raised when expected. Then I'll merge and commit.

Cheers!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/mailman/app/membership.py'
2--- src/mailman/app/membership.py 2011-05-26 01:30:56 +0000
3+++ src/mailman/app/membership.py 2011-08-25 23:41:30 +0000
4@@ -43,7 +43,8 @@
5
6
7
8
9-def add_member(mlist, email, realname, password, delivery_mode, language):
10+def add_member(mlist, email, realname, password, delivery_mode, language,
11+ role=MemberRole.member):
12 """Add a member right now.
13
14 The member's subscription must be approved by whatever policy the list
15@@ -70,9 +71,6 @@
16 """
17 # Let's be extra cautious.
18 getUtility(IEmailValidator).validate(email)
19- if mlist.members.get_member(email) is not None:
20- raise AlreadySubscribedError(
21- mlist.fqdn_listname, email, MemberRole.member)
22 # Check to see if the email address is banned.
23 if getUtility(IBanManager).is_banned(email, mlist.fqdn_listname):
24 raise MembershipIsBannedError(mlist, email)
25@@ -99,7 +97,7 @@
26 # scheme is recorded in the hashed password string.
27 user.password = encrypt_password(password)
28 user.preferences.preferred_language = language
29- member = mlist.subscribe(address, MemberRole.member)
30+ member = mlist.subscribe(address, role)
31 member.preferences.delivery_mode = delivery_mode
32 else:
33 # The user exists and is linked to the address.
34@@ -110,7 +108,7 @@
35 raise AssertionError(
36 'User should have had linked address: {0}'.format(address))
37 # Create the member and set the appropriate preferences.
38- member = mlist.subscribe(address, MemberRole.member)
39+ member = mlist.subscribe(address, role)
40 member.preferences.preferred_language = language
41 member.preferences.delivery_mode = delivery_mode
42 return member
43
44=== modified file 'src/mailman/app/subscriptions.py'
45--- src/mailman/app/subscriptions.py 2011-08-17 23:22:45 +0000
46+++ src/mailman/app/subscriptions.py 2011-08-25 23:41:30 +0000
47@@ -37,7 +37,7 @@
48 from mailman.interfaces.address import InvalidEmailAddressError
49 from mailman.interfaces.listmanager import (
50 IListManager, ListDeletedEvent, NoSuchListError)
51-from mailman.interfaces.member import DeliveryMode
52+from mailman.interfaces.member import DeliveryMode, MemberRole
53 from mailman.interfaces.subscriptions import (
54 ISubscriptionService, MissingUserError)
55 from mailman.interfaces.usermanager import IUserManager
56@@ -138,16 +138,12 @@
57 for member in self.get_members():
58 yield member
59
60- def join(self, fqdn_listname, subscriber,
61- real_name= None, delivery_mode=None):
62+ def join(self, fqdn_listname, subscriber, real_name= None,
63+ delivery_mode=DeliveryMode.regular, role=MemberRole.member):
64 """See `ISubscriptionService`."""
65 mlist = getUtility(IListManager).get(fqdn_listname)
66 if mlist is None:
67 raise NoSuchListError(fqdn_listname)
68- # Convert from string to enum.
69- mode = (DeliveryMode.regular
70- if delivery_mode is None
71- else delivery_mode)
72 # Is the subscriber a user or email address?
73 if '@' in subscriber:
74 # It's an email address, so we'll want a real name.
75@@ -163,14 +159,15 @@
76 # it can't be retrieved. Note that none of these are used unless
77 # the address is completely new to us.
78 password = make_user_friendly_password()
79- return add_member(mlist, subscriber, real_name, password, mode,
80- system_preferences.preferred_language)
81+ return add_member(mlist, subscriber, real_name, password,
82+ delivery_mode,
83+ system_preferences.preferred_language, role)
84 else:
85 # We have to assume it's a user id.
86 user = getUtility(IUserManager).get_user_by_id(subscriber)
87 if user is None:
88 raise MissingUserError(subscriber)
89- return mlist.subscribe(user)
90+ return mlist.subscribe(user, role)
91
92 def leave(self, fqdn_listname, address):
93 """See `ISubscriptionService`."""
94
95=== modified file 'src/mailman/app/tests/test_membership.py'
96--- src/mailman/app/tests/test_membership.py 2011-04-09 00:09:13 +0000
97+++ src/mailman/app/tests/test_membership.py 2011-08-25 23:41:30 +0000
98@@ -34,7 +34,8 @@
99 from mailman.config import config
100 from mailman.core.constants import system_preferences
101 from mailman.interfaces.bans import IBanManager
102-from mailman.interfaces.member import DeliveryMode, MembershipIsBannedError
103+from mailman.interfaces.member import (DeliveryMode, MembershipIsBannedError,
104+ MemberRole)
105 from mailman.interfaces.usermanager import IUserManager
106 from mailman.testing.helpers import reset_the_world
107 from mailman.testing.layers import ConfigLayer
108@@ -58,6 +59,7 @@
109 system_preferences.preferred_language)
110 self.assertEqual(member.address.email, 'aperson@example.com')
111 self.assertEqual(member.mailing_list, 'test@example.com')
112+ self.assertEqual(member.role, MemberRole.member)
113
114 def test_add_member_existing_user(self):
115 # Test subscribing a user to a mailing list when the email address has
116@@ -124,6 +126,16 @@
117 system_preferences.preferred_language)
118 self.assertEqual(member.address.email, 'anne@example.com')
119
120+ def test_add_member_moderator(self):
121+ # Test adding a moderator to a mailing list
122+ member = add_member(self._mlist, 'aperson@example.com',
123+ 'Anne Person', '123', DeliveryMode.regular,
124+ system_preferences.preferred_language,
125+ MemberRole.moderator)
126+ self.assertEqual(member.address.email, 'aperson@example.com')
127+ self.assertEqual(member.mailing_list, 'test@example.com')
128+ self.assertEqual(member.role, MemberRole.moderator)
129+
130
131
132
133 class AddMemberPasswordTest(unittest.TestCase):
134
135=== modified file 'src/mailman/interfaces/subscriptions.py'
136--- src/mailman/interfaces/subscriptions.py 2011-08-17 23:10:39 +0000
137+++ src/mailman/interfaces/subscriptions.py 2011-08-25 23:41:30 +0000
138@@ -28,6 +28,7 @@
139 from zope.interface import Interface
140
141 from mailman.interfaces.errors import MailmanError
142+from mailman.interfaces.member import DeliveryMode, MemberRole
143
144
145
146
147@@ -91,7 +92,8 @@
148 def __iter__():
149 """See `get_members()`."""
150
151- def join(fqdn_listname, subscriber, real_name=None, delivery_mode=None):
152+ def join(fqdn_listname, subscriber, real_name=None,
153+ delivery_mode=DeliveryMode.regular, role=MemberRole.member):
154 """Subscribe to a mailing list.
155
156 A user for the address is created if it is not yet known to Mailman,
157
158=== modified file 'src/mailman/rest/docs/membership.rst'
159--- src/mailman/rest/docs/membership.rst 2011-08-17 23:10:39 +0000
160+++ src/mailman/rest/docs/membership.rst 2011-08-25 23:41:30 +0000
161@@ -197,8 +197,27 @@
162 mailing list.
163 ::
164
165- >>> subscribe(ant, 'Dave', MemberRole.moderator)
166- >>> subscribe(bee, 'Cris', MemberRole.owner)
167+ >>> dump_json('http://localhost:9001/3.0/members', {
168+ ... 'fqdn_listname': 'ant@example.com',
169+ ... 'subscriber': 'dperson@example.com',
170+ ... 'role': 'moderator',
171+ ... })
172+ content-length: 0
173+ date: ...
174+ location: http://localhost:9001/3.0/members/6
175+ server: ...
176+ status: 201
177+
178+ >>> dump_json('http://localhost:9001/3.0/members', {
179+ ... 'fqdn_listname': 'bee@example.com',
180+ ... 'subscriber': 'cperson@example.com',
181+ ... 'role': 'owner',
182+ ... })
183+ content-length: 0
184+ date: ...
185+ location: http://localhost:9001/3.0/members/7
186+ server: ...
187+ status: 201
188
189 >>> dump_json('http://localhost:9001/3.0/members')
190 entry 0:
191
192=== modified file 'src/mailman/rest/members.py'
193--- src/mailman/rest/members.py 2011-08-17 23:10:39 +0000
194+++ src/mailman/rest/members.py 2011-08-25 23:41:30 +0000
195@@ -151,7 +151,8 @@
196 subscriber=unicode,
197 real_name=unicode,
198 delivery_mode=enum_validator(DeliveryMode),
199- _optional=('delivery_mode', 'real_name'))
200+ role=enum_validator(MemberRole),
201+ _optional=('delivery_mode', 'real_name', 'role'))
202 member = service.join(**validator(request))
203 except AlreadySubscribedError:
204 return http.conflict([], b'Member already subscribed')