136
96
with self.assertRaises(HTTPError) as cm:
137
97
call_api(url, dict(action='discard'))
138
98
self.assertEqual(cm.exception.code, 404)
102
class TestSubscriptionModeration(unittest.TestCase):
108
self._mlist = create_list('ant@example.com')
109
self._registrar = IRegistrar(self._mlist)
110
manager = getUtility(IUserManager)
111
self._anne = manager.create_address(
112
'anne@example.com', 'Anne Person')
113
self._bart = manager.make_user(
114
'bart@example.com', 'Bart Person')
115
preferred = list(self._bart.addresses)[0]
116
preferred.verified_on = now()
117
self._bart.preferred_address = preferred
119
def test_no_such_list(self):
120
# Try to get the requests of a nonexistent list.
121
with self.assertRaises(HTTPError) as cm:
122
call_api('http://localhost:9001/3.0/lists/bee@example.com/'
124
self.assertEqual(cm.exception.code, 404)
126
def test_no_such_subscription_token(self):
127
# Bad request when the token is not in the database.
128
with self.assertRaises(HTTPError) as cm:
129
call_api('http://localhost:9001/3.0/lists/ant@example.com/'
131
self.assertEqual(cm.exception.code, 404)
133
def test_bad_subscription_action(self):
134
# POSTing to a held message with a bad action.
135
token, token_owner, member = self._registrar.register(self._anne)
136
# Anne's subscription request got held.
137
self.assertIsNone(member)
138
# Let's try to handle her request, but with a bogus action.
139
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
140
with self.assertRaises(HTTPError) as cm:
141
call_api(url.format(token), dict(
144
self.assertEqual(cm.exception.code, 400)
145
self.assertEqual(cm.exception.msg,
146
b'Cannot convert parameters: action')
148
def test_list_held_requests(self):
149
# We can view all the held requests.
151
token_1, token_owner, member = self._registrar.register(self._anne)
152
# Anne's subscription request got held.
153
self.assertIsNotNone(token_1)
154
self.assertIsNone(member)
155
token_2, token_owner, member = self._registrar.register(self._bart)
156
self.assertIsNotNone(token_2)
157
self.assertIsNone(member)
158
content, response = call_api(
159
'http://localhost:9001/3.0/lists/ant@example.com/requests')
160
self.assertEqual(response.status, 200)
161
self.assertEqual(content['total_size'], 2)
162
tokens = set(json['token'] for json in content['entries'])
163
self.assertEqual(tokens, {token_1, token_2})
164
emails = set(json['email'] for json in content['entries'])
165
self.assertEqual(emails, {'anne@example.com', 'bart@example.com'})
167
def test_individual_request(self):
168
# We can view an individual request.
170
token, token_owner, member = self._registrar.register(self._anne)
171
# Anne's subscription request got held.
172
self.assertIsNotNone(token)
173
self.assertIsNone(member)
174
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
175
content, response = call_api(url.format(token))
176
self.assertEqual(response.status, 200)
177
self.assertEqual(content['token'], token)
178
self.assertEqual(content['token_owner'], token_owner.name)
179
self.assertEqual(content['email'], 'anne@example.com')
181
def test_accept(self):
182
# POST to the request to accept it.
184
token, token_owner, member = self._registrar.register(self._anne)
185
# Anne's subscription request got held.
186
self.assertIsNone(member)
187
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
188
content, response = call_api(url.format(token), dict(
191
self.assertEqual(response.status, 204)
194
self._mlist.members.get_member('anne@example.com').address,
196
# The request URL no longer exists.
197
with self.assertRaises(HTTPError) as cm:
198
call_api(url.format(token), dict(
201
self.assertEqual(cm.exception.code, 404)
203
def test_accept_bad_token(self):
204
# Try to accept a request with a bogus token.
205
with self.assertRaises(HTTPError) as cm:
206
call_api('http://localhost:9001/3.0/lists/ant@example.com'
208
dict(action='accept'))
209
self.assertEqual(cm.exception.code, 404)
211
def test_accept_by_moderator_clears_request_queue(self):
212
# After accepting a message held for moderator approval, there are no
213
# more requests to handle.
215
# We start with nothing in the queue.
216
content, response = call_api(
217
'http://localhost:9001/3.0/lists/ant@example.com/requests')
218
self.assertEqual(content['total_size'], 0)
219
# Anne tries to subscribe to a list that only requests moderator
222
self._mlist.subscription_policy = SubscriptionPolicy.moderate
223
token, token_owner, member = self._registrar.register(
225
pre_verified=True, pre_confirmed=True)
226
# There's now one request in the queue, and it's waiting on moderator
228
content, response = call_api(
229
'http://localhost:9001/3.0/lists/ant@example.com/requests')
230
self.assertEqual(content['total_size'], 1)
231
json = content['entries'][0]
232
self.assertEqual(json['token_owner'], 'moderator')
233
self.assertEqual(json['email'], 'anne@example.com')
234
# The moderator approves the request.
235
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
236
content, response = call_api(url.format(token), {'action': 'accept'})
237
self.assertEqual(response.status, 204)
238
# And now the request queue is empty.
239
content, response = call_api(
240
'http://localhost:9001/3.0/lists/ant@example.com/requests')
241
self.assertEqual(content['total_size'], 0)
243
def test_discard(self):
244
# POST to the request to discard it.
246
token, token_owner, member = self._registrar.register(self._anne)
247
# Anne's subscription request got held.
248
self.assertIsNone(member)
249
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
250
content, response = call_api(url.format(token), dict(
253
self.assertEqual(response.status, 204)
254
# Anne is not a member.
255
self.assertIsNone(self._mlist.members.get_member('anne@example.com'))
256
# The request URL no longer exists.
257
with self.assertRaises(HTTPError) as cm:
258
call_api(url.format(token), dict(
261
self.assertEqual(cm.exception.code, 404)
263
def test_defer(self):
264
# Defer the decision for some other moderator.
266
token, token_owner, member = self._registrar.register(self._anne)
267
# Anne's subscription request got held.
268
self.assertIsNone(member)
269
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
270
content, response = call_api(url.format(token), dict(
273
self.assertEqual(response.status, 204)
274
# Anne is not a member.
275
self.assertIsNone(self._mlist.members.get_member('anne@example.com'))
276
# The request URL still exists.
277
content, response = call_api(url.format(token), dict(
280
self.assertEqual(response.status, 204)
281
# And now we can accept it.
282
content, response = call_api(url.format(token), dict(
285
self.assertEqual(response.status, 204)
288
self._mlist.members.get_member('anne@example.com').address,
290
# The request URL no longer exists.
291
with self.assertRaises(HTTPError) as cm:
292
call_api(url.format(token), dict(
295
self.assertEqual(cm.exception.code, 404)
297
def test_defer_bad_token(self):
298
# Try to accept a request with a bogus token.
299
with self.assertRaises(HTTPError) as cm:
300
call_api('http://localhost:9001/3.0/lists/ant@example.com'
302
dict(action='defer'))
303
self.assertEqual(cm.exception.code, 404)
305
def test_reject(self):
306
# POST to the request to reject it. This leaves a bounce message in
309
token, token_owner, member = self._registrar.register(self._anne)
310
# Anne's subscription request got held.
311
self.assertIsNone(member)
312
# Clear out the virgin queue, which currently contains the
313
# confirmation message sent to Anne.
314
get_queue_messages('virgin')
315
url = 'http://localhost:9001/3.0/lists/ant@example.com/requests/{}'
316
content, response = call_api(url.format(token), dict(
319
self.assertEqual(response.status, 204)
320
# Anne is not a member.
321
self.assertIsNone(self._mlist.members.get_member('anne@example.com'))
322
# The request URL no longer exists.
323
with self.assertRaises(HTTPError) as cm:
324
call_api(url.format(token), dict(
327
self.assertEqual(cm.exception.code, 404)
328
# And the rejection message to Anne is now in the virgin queue.
329
items = get_queue_messages('virgin')
330
self.assertEqual(len(items), 1)
331
message = items[0].msg
332
self.assertEqual(message['From'], 'ant-bounces@example.com')
333
self.assertEqual(message['To'], 'anne@example.com')
334
self.assertEqual(message['Subject'],
335
'Request to mailing list "Ant" rejected')
337
def test_reject_bad_token(self):
338
# Try to accept a request with a bogus token.
339
with self.assertRaises(HTTPError) as cm:
340
call_api('http://localhost:9001/3.0/lists/ant@example.com'
342
dict(action='reject'))
343
self.assertEqual(cm.exception.code, 404)