1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2021 by the Free Software Foundation, Inc.
4 # This file is part of Postorius.
6 # Postorius is free software: you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free
8 # Software Foundation, either version 3 of the License, or (at your option)
10 # Postorius is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # Postorius. If not, see <http://www.gnu.org/licenses/>.
19 from django
.contrib
.auth
.models
import User
20 from django
.test
.utils
import override_settings
21 from django
.urls
import reverse
23 from allauth
.account
.models
import EmailAddress
24 from django_mailman3
.lib
.mailman
import get_mailman_user
26 from postorius
.forms
import ChangeSubscriptionForm
, UserPreferences
27 from postorius
.models
import Mailman404Error
, MailmanUser
28 from postorius
.tests
.utils
import ViewTestCase
31 class MailmanUserTest(ViewTestCase
):
33 Tests for the mailman user preferences settings page.
37 super(MailmanUserTest
, self
).setUp()
38 self
.domain
= self
.mm_client
.create_domain('example.com')
39 self
.foo_list
= self
.domain
.create_list('foo')
40 self
.foo_list
.send_welcome_message
= False
41 self
.user
= User
.objects
.create_user(
42 'user', 'user@example.com', 'testpass')
43 EmailAddress
.objects
.create(
44 user
=self
.user
, email
=self
.user
.email
, verified
=True, primary
=True)
45 self
.mm_user
= get_mailman_user(self
.user
)
47 def test_address_preferences_not_logged_in(self
):
48 self
.assertRedirectsToLogin(reverse('user_address_preferences'))
50 def test_subscriptions_not_logged_in(self
):
51 self
.assertRedirectsToLogin(reverse('ps_user_profile'))
53 def test_subscriptions_logged_in(self
):
54 self
.client
.login(username
='user', password
='testpass')
55 response
= self
.client
.get(reverse('ps_user_profile'))
56 self
.assertEqual(response
.status_code
, 200)
58 def test_address_based_preferences(self
):
59 self
.client
.login(username
='user', password
='testpass')
60 self
.mm_user
.add_address('user2@example.com')
61 self
.mm_user
.add_address('user3@example.com')
62 response
= self
.client
.get(reverse('user_address_preferences'))
63 self
.assertEqual(response
.status_code
, 200)
64 self
.assertEqual(len(response
.context
["formset"]), 3)
66 # this test needs re-thinking with the way we've hacked preferences
67 # it has been disabled for now
68 # def test_preferences_none(self):
69 # # Mailman does not accept None values for boolean preferences. When
70 # # those preferences are unset, they must be excluded from the POST
72 # self.client.login(username='user', password='testpass')
73 # self.foo_list.subscribe(self.user.email, pre_verified=True,
74 # pre_confirmed=True, pre_approved=True)
76 # 'receive_own_postings', 'acknowledge_posts',
77 # 'hide_address', 'receive_list_copy',
79 # # Prepare a Preferences subclass that will check the POST data
80 # import mailmanclient._client
82 # class TestingPrefs(mailmanclient._client.Preferences):
86 # for pref in prefs_with_none:
87 # self.testcase.assertNotIn(pref, self._changed_rest_data)
88 # # Now check the relevant URLs
89 # with patch('mailmanclient._client.Preferences') as pref_class:
90 # pref_class.side_effect = TestingPrefs
93 # reverse('user_mailmansettings'),
94 # reverse('user_list_options',
95 # args=[self.foo_list.list_id]),
97 # response = self.client.post(
98 # url, dict((pref, None) for pref in prefs_with_none))
99 # self.assertEqual(response.status_code, 302)
101 # for url in ('user_address_preferences',
102 # 'user_subscription_preferences'):
105 # ('form-0-%s' % pref, None)
106 # for pref in prefs_with_none)
108 # 'form-TOTAL_FORMS': '1',
109 # 'form-INITIAL_FORMS': '0',
110 # 'form-MAX_NUM_FORMS': ''
112 # response = self.client.post(url, post_data)
113 # self.assertEqual(response.status_code, 302)
115 @override_settings(AUTOCREATE_MAILMAN_USER
=False)
116 def test_subscriptions_no_mailman_user(self
):
117 # Existing Django users without a corresponding Mailman user must not
118 # cause views to crash.
119 user
= User
.objects
.create_user(
120 'old-user', 'old-user@example.com', 'testpass')
121 EmailAddress
.objects
.create(
122 user
=user
, email
=user
.email
, verified
=True)
123 self
.client
.login(username
='old-user', password
='testpass')
124 self
.assertRaises(Mailman404Error
, MailmanUser
.objects
.get
,
126 response
= self
.client
.get(reverse('ps_user_profile'))
127 self
.assertEqual(response
.status_code
, 200)
128 # The Mailman user must have been created
129 self
.assertIsNotNone(MailmanUser
.objects
.get(address
=user
.email
))
131 def test_presence_of_form_in_user_global_settings(self
):
132 self
.client
.login(username
='user', password
='testpass')
133 response
= self
.client
.get(reverse('user_mailmansettings'))
134 self
.assertEqual(response
.status_code
, 200)
135 self
.assertIsInstance(response
.context
['form'], UserPreferences
)
137 def test_presence_of_form_in_user_subscription_preferences(self
):
138 self
.client
.login(username
='user', password
='testpass')
139 self
.foo_list
.subscribe(self
.user
.email
, pre_verified
=True,
140 pre_confirmed
=True, pre_approved
=True)
141 response
= self
.client
.get(reverse('user_subscription_preferences'))
142 self
.assertEqual(response
.status_code
, 200)
143 self
.assertIsNotNone(response
.context
['formset'])
144 self
.assertEqual(len(response
.context
['formset']), 1)
146 def test_presence_of_form_in_user_list_options(self
):
147 self
.client
.login(username
='user', password
='testpass')
148 member
= self
.foo_list
.subscribe(
150 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
151 response
= self
.client
.get(reverse('user_list_options',
152 args
=[member
.member_id
]))
153 self
.assertEqual(response
.status_code
, 200)
154 self
.assertIsInstance(response
.context
['form'],
156 self
.assertIsInstance(response
.context
['change_subscription_form'],
157 ChangeSubscriptionForm
)
159 def test_list_options_shows_all_addresses(self
):
160 self
.client
.login(username
='user', password
='testpass')
161 member
= self
.foo_list
.subscribe(self
.user
.email
, pre_verified
=True,
162 pre_confirmed
=True, pre_approved
=True)
164 EmailAddress
.objects
.create(
165 user
=self
.user
, email
='anotheremail@example.com', verified
=True)
166 user
= self
.mm_client
.get_user('user@example.com')
167 address
= user
.add_address('anotheremail@example.com')
170 response
= self
.client
.get(reverse('user_list_options',
171 args
=[member
.member_id
]))
172 self
.assertEqual(response
.status_code
, 200)
173 self
.assertContains(response
, 'anotheremail@example.com')
175 def _set_primary(self
, user
, mm_user
):
176 for addr
in mm_user
.addresses
:
178 mm_user
.preferred_address
= user
.email
180 def test_change_subscription_to_new_email(self
):
181 # Test that we can change subscription to a new email.
182 self
.client
.login(username
='user', password
='testpass')
183 user
= self
.mm_client
.get_user('user@example.com')
184 EmailAddress
.objects
.create(
185 user
=self
.user
, email
='anotheremail@example.com', verified
=True)
186 address
= user
.add_address('anotheremail@example.com')
188 member
= self
.foo_list
.subscribe(
190 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
191 # Now, first verify that the list_options page has all the emails.
193 response
= self
.client
.get(reverse('user_list_options',
194 args
=[member
.member_id
]))
195 self
.assertContains(response
, 'anotheremail@example.com')
198 '<option value="user@example.com"'
199 ' selected>user@example.com</option>')
200 member
= self
.mm_client
.get_member(
201 self
.foo_list
.list_id
, 'user@example.com')
202 self
.assertIsNotNone(member
)
203 # Initially, all preferences are none. Let's set it to something
205 self
.assertIsNone(member
.preferences
.get('acknowledge_posts'))
206 member
.preferences
['acknowledge_posts'] = True
207 member
.preferences
.save()
208 # now, let's switch the subscription to a new user.
209 response
= self
.client
.post(
210 reverse('change_subscription', args
=(self
.foo_list
.list_id
, )),
211 {'subscriber': 'anotheremail@example.com',
212 'member_id': member
.member_id
}
214 self
.assertEqual(response
.status_code
, 302)
215 self
.assertHasSuccessMessage(response
)
216 member_new
= self
.mm_client
.get_member(
217 self
.foo_list
.list_id
, 'anotheremail@example.com')
218 self
.assertIsNotNone(member_new
)
219 # There is no 'member_id' attribute, so we simply use the self_link to
220 # compare and make sure that the Member object is same.
221 self
.assertEqual(member
.self_link
, member_new
.self_link
)
222 self
.assertEqual(member_new
.subscription_mode
, 'as_address')
223 # Also, assert that the new member's preferences are same.
224 self
.assertEqual(member
.preferences
['acknowledge_posts'],
225 member_new
.preferences
['acknowledge_posts'])
227 def test_change_subscription_to_from_primary_address(self
):
228 # Test that we can change subscription to a new email.
229 self
.client
.login(username
='user', password
='testpass')
230 user
= self
.mm_client
.get_user('user@example.com')
231 self
._set
_primary
(self
.user
, user
)
232 member
= self
.foo_list
.subscribe(
234 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
235 # Now, first verify that the list_options page has the primary address.
236 response
= self
.client
.get(reverse('user_list_options',
237 args
=[member
.member_id
]))
238 self
.assertContains(response
, 'Primary Address (user@example.com)')
241 '<option value="user@example.com" '
242 'selected>user@example.com</option>')
243 member
= self
.mm_client
.get_member(
244 self
.foo_list
.list_id
, 'user@example.com')
245 self
.assertIsNotNone(member
)
246 # Initially, all preferences are none. Let's set it to something
248 self
.assertIsNone(member
.preferences
.get('acknowledge_posts'))
249 member
.preferences
['acknowledge_posts'] = True
250 member
.preferences
.save()
251 # now, let's switch the subscription to a new user.
252 response
= self
.client
.post(
253 reverse('change_subscription', args
=(self
.foo_list
.list_id
, )),
254 {'subscriber': str(user
.user_id
), 'member_id': member
.member_id
}
256 self
.assertEqual(response
.status_code
, 302)
257 self
.assertHasSuccessMessage(response
)
258 new_member
= self
.mm_client
.get_member(
259 self
.foo_list
.list_id
, 'user@example.com')
260 self
.assertIsNotNone(new_member
)
261 self
.assertEqual(new_member
.subscription_mode
, 'as_user')
262 # we can't compare against the preferences object of `member` since the
263 # resource is now Deleted due to unsubscribe-subscribe dance.
264 self
.assertEqual(new_member
.preferences
['acknowledge_posts'], True)
266 def test_already_subscribed(self
):
267 self
.client
.login(username
='user', password
='testpass')
269 member
= self
.foo_list
.subscribe(
271 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
272 # Now, first verify that the list_options page has all the emails.
274 response
= self
.client
.get(reverse('user_list_options',
275 args
=[member
.member_id
]))
278 '<option value="user@example.com" '
279 'selected>user@example.com</option>')
280 # now, let's switch the subscription to a new user.
281 response
= self
.client
.post(
282 reverse('change_subscription', args
=(self
.foo_list
.list_id
, )),
283 {'subscriber': 'user@example.com', 'member_id': member
.member_id
}
285 self
.assertEqual(response
.status_code
, 302)
286 error
= self
.assertHasErrorMessage(response
)
287 self
.assertIn('You are already subscribed', error
)
289 def test_already_subscribed_with_primary_address(self
):
290 # Test that we can change subscription to a new email.
291 self
.client
.login(username
='user', password
='testpass')
292 user
= self
.mm_client
.get_user('user@example.com')
293 self
._set
_primary
(self
.user
, user
)
294 member
= self
.foo_list
.subscribe(
296 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
297 # Now, first verify that the list_options page has the primary address.
298 response
= self
.client
.get(reverse('user_list_options',
299 args
=[member
.member_id
]))
302 ('<option value="{}" selected>Primary Address (user@example.com)'
303 '</option>').format(user
.user_id
))
304 # now, let's switch the subscription to a new user.
305 response
= self
.client
.post(
306 reverse('change_subscription', args
=(self
.foo_list
.list_id
, )),
307 {'subscriber': str(user
.user_id
), 'member_id': member
.member_id
}
309 self
.assertEqual(response
.status_code
, 302)
310 error
= self
.assertHasErrorMessage(response
)
311 self
.assertIn('You are already subscribed', error
)
313 def test_list_options_sets_preferred_address(self
):
314 # Test that preferred address is set.
315 mm_user
= get_mailman_user(self
.user
)
316 self
.assertIsNone(mm_user
.preferred_address
)
317 member
= self
.foo_list
.subscribe(
319 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
320 self
.client
.login(username
='user', password
='testpass')
321 self
.client
.get(reverse('user_list_options',
322 args
=[member
.member_id
]))
323 self
.assertEqual(mm_user
.preferred_address
.email
, self
.user
.email
)
325 def test_access_list_options_multiple_subscriptions(self
):
326 # Test that when multiple addresses of a single user are subscribed to
327 # the same list that they are able to access them.
328 mm_user
= get_mailman_user(self
.user
)
329 self
.assertIsNone(mm_user
.preferred_address
)
330 self
._set
_primary
(self
.user
, mm_user
)
331 # Subscribe the user twice, once with their address and then with their
333 member_primary
= self
.foo_list
.subscribe(
335 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
336 member_addr
= self
.foo_list
.subscribe(
338 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
339 self
.assertEqual(len(self
.foo_list
.members
), 2)
341 self
.client
.login(username
='user', password
='testpass')
342 response
= self
.client
.get(
343 reverse('user_subscription_preferences'))
344 self
.assertEqual(response
.status_code
, 200)
345 # There should be list options for two users.
346 self
.assertContains(response
, 'Primary Address')
347 self
.assertContains(response
, 'user@example.com')
348 # Get the list options for both memberships and check subscriber ==
350 response
= self
.client
.get(
351 reverse('user_list_options',
352 args
=[member_addr
.member_id
]))
353 self
.assertEqual(response
.status_code
, 200)
354 subscriber
= response
.context
.get(
355 'change_subscription_form').initial
.get('subscriber')
356 self
.assertEqual(subscriber
, member_addr
.address
.email
)
357 # Check subscriber == member_id
358 response
= self
.client
.get(
359 reverse('user_list_options',
360 args
=[member_primary
.member_id
]))
361 self
.assertEqual(response
.status_code
, 200)
362 subscriber
= response
.context
.get(
363 'change_subscription_form').initial
.get('subscriber')
364 self
.assertEqual(subscriber
, member_primary
.user
.user_id
)
366 def test_access_list_options_other_member(self
):
367 # Test that a user can't access member options for a different user.
368 member_addr
= self
.foo_list
.subscribe(
370 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
371 another_member
= self
.foo_list
.subscribe(
372 'anoter@example.com',
373 pre_verified
=True, pre_confirmed
=True, pre_approved
=True)
374 self
.client
.login(username
='user', password
='testpass')
375 response
= self
.client
.get(
376 reverse('user_list_options',
377 args
=[another_member
.member_id
]))
378 self
.assertEqual(response
.status_code
, 404)
379 # But they can access their own.
380 response
= self
.client
.get(
381 reverse('user_list_options',
382 args
=[member_addr
.member_id
]))
383 self
.assertEqual(response
.status_code
, 200)
386 class TestListAllUsers(ViewTestCase
):
391 self
.mm_client
.create_user('user{}@example.com'.format(i
),
394 self
.su
= User
.objects
.create_superuser('su', 'su@example.com', 'pass')
396 def test_get_all_users_forbidden(self
):
397 response
= self
.client
.get(reverse('list_users'))
398 self
.assertEqual(response
.status_code
, 403)
400 def test_get_all_users_as_superuser(self
):
401 self
.client
.force_login(self
.su
)
402 url
= reverse('list_users')
403 response
= self
.client
.get(url
)
404 self
.assertEqual(response
.status_code
, 200)
405 # default page size is 10, so we will get 10.
406 self
.assertEqual(len(response
.context
['all_users']), 10)
407 # lets get all users by setting count.
409 response
= self
.client
.get(url
)
410 self
.assertEqual(response
.status_code
, 200)
411 # default page size is 10, so we will get 10.
412 self
.assertEqual(len(response
.context
['all_users']), 11)
414 def test_search_user(self
):
415 self
.client
.force_login(self
.su
)
418 return reverse('list_users') + '?q={}'.format(query
)
420 response
= self
.client
.get(_get_url('0@e'))
421 self
.assertEqual(response
.status_code
, 200)
422 # It should be two users, user0@example.com and user10@example.com
423 self
.assertEqual(len(response
.context
['all_users']), 2)
424 # search with display name.
425 response
= self
.client
.get(_get_url('User 7'))
426 self
.assertEqual(response
.status_code
, 200)
427 # It should be one user, user7@example.com, but it should search with
428 # display name because of the space.
429 self
.assertEqual(len(response
.context
['all_users']), 1)
430 self
.assertEqual(response
.context
['all_users'][0].display_name
,
434 class TestManageUser(ViewTestCase
):
438 self
.user
= self
.mm_client
.create_user('user@example.com',
440 self
.su
= User
.objects
.create_superuser('su', 'su@example.com', 'pass')
441 dom
= self
.mm_client
.create_domain('example.com')
442 self
.mlist
= dom
.create_list('test')
443 self
.mlist
.subscribe('user@example.com',
444 pre_verified
=True, pre_confirmed
=True)
446 def test_get_all_users_forbidden(self
):
447 response
= self
.client
.get(
448 reverse('manage_user', args
=[self
.user
.user_id
]))
449 self
.assertEqual(response
.status_code
, 403)
451 def test_get_manage_user(self
):
452 self
.client
.force_login(self
.su
)
453 response
= self
.client
.get(
454 reverse('manage_user', args
=[self
.user
.user_id
]))
455 self
.assertEqual(response
.status_code
, 200)
456 self
.assertEqual(response
.context
['auser'].user_id
, self
.user
.user_id
)
457 user_form
= response
.context
['user_form']
458 self
.assertEqual(user_form
.user
.user_id
, self
.user
.user_id
)
459 addr_forms
= response
.context
['addresses']
460 self
.assertEqual(len(addr_forms
.forms
), 1)
461 subform
= response
.context
['subscriptions']
462 self
.assertEqual(len(subform
.forms
), 1)
463 self
.assertIsNone(response
.context
['django_user'])
464 self
.assertIsNone(response
.context
['change_password'])
466 def test_get_manage_user_with_django_user(self
):
467 user
= User
.objects
.create_user(username
='tester', password
='test')
468 for addr
in self
.user
.addresses
:
469 EmailAddress
.objects
.create(
470 user
=user
, email
=addr
.email
)
471 self
.client
.force_login(self
.su
)
472 response
= self
.client
.get(
473 reverse('manage_user', args
=[self
.user
.user_id
]))
474 self
.assertEqual(response
.status_code
, 200)
475 self
.assertEqual(response
.context
['auser'].user_id
, self
.user
.user_id
)
476 user_form
= response
.context
['user_form']
477 self
.assertEqual(user_form
.user
.user_id
, self
.user
.user_id
)
478 addr_forms
= response
.context
['addresses']
479 self
.assertEqual(len(addr_forms
.forms
), 1)
480 subform
= response
.context
['subscriptions']
481 self
.assertEqual(len(subform
.forms
), 1)
482 self
.assertEqual(response
.context
['django_user'], user
)
483 self
.assertIsNotNone(response
.context
['change_password'])
485 def test_update_display_name(self
):
486 self
.client
.force_login(self
.su
)
487 response
= self
.client
.post(
488 reverse('manage_user', args
=[self
.user
.user_id
]),
489 data
={'display_name': 'My User', 'user_form': 'Update'})
490 self
.assertEqual(response
.status_code
, 200)
491 self
.assertIn('Successfully updated user.', response
.content
.decode())
493 def test_update_user_address(self
):
494 self
.client
.force_login(self
.su
)
495 addresses
= self
.user
.addresses
496 addresses
[0].unverify()
497 self
.assertFalse(self
.user
.addresses
[0].verified
)
499 'form-TOTAL_FORMS': '1',
500 'form-INITIAL_FORMS': '1',
501 'form-MIN_NUM_FORMS': '1',
502 'form-MAX_NUM_FORMS': '1',
503 'form-0-verified': 'on',
504 'address_form': 'Update',
506 response
= self
.client
.post(
507 reverse('manage_user', args
=[self
.user
.user_id
]),
509 self
.assertEqual(response
.status_code
, 200)
510 self
.assertTrue(self
.user
.addresses
[0].verified
)
511 self
.assertIn('Successfully updated addresses user@example.com',
512 response
.content
.decode())
514 def test_update_user_subscriptions(self
):
515 self
.client
.force_login(self
.su
)
517 'form-TOTAL_FORMS': '1',
518 'form-INITIAL_FORMS': '1',
519 'form-MIN_NUM_FORMS': '0',
520 'form-MAX_NUM_FORMS': '1',
522 'form-0-moderation_action': 'discard',
523 'form-0-delivery_mode': 'mime_digests',
524 'subs_form': 'Update',
526 response
= self
.client
.post(
527 reverse('manage_user', args
=[self
.user
.user_id
]),
529 self
.assertEqual(response
.status_code
, 200)
530 self
.assertIn('Successfully updated memberships for test.example.com',
531 response
.content
.decode())
533 def test_update_user_password(self
):
534 user
= User
.objects
.create_user(
535 username
='myuser', password
='mypassword')
536 EmailAddress
.objects
.create(user
=user
, email
='user@example.com')
538 self
.client
.login(username
='myuser', password
='mypassword'))
539 self
.client
.force_login(self
.su
)
541 'change_password': 'Update',
542 'password1': 'newpsdsd1987',
543 'password2': 'newpsdsd1987',
545 response
= self
.client
.post(
546 reverse('manage_user', args
=[self
.user
.user_id
]),
548 self
.assertEqual(response
.status_code
, 200)
549 # Verify by tring to login.
551 self
.client
.login(username
='myuser', password
='newpsdsd1987'))