1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2017-2019 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)
11 # Postorius is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 # You should have received a copy of the GNU General Public License along with
17 # Postorius. If not, see <http://www.gnu.org/licenses/>.
21 from django
.test
import TestCase
23 from postorius
.forms
.list_forms
import (
24 ArchiveSettingsForm
, ChangeSubscriptionForm
, DigestSettingsForm
,
25 DMARCMitigationsForm
, ListAnonymousSubscribe
, ListAutomaticResponsesForm
,
26 ListHeaderMatchForm
, ListIdentityForm
, ListMassRemoval
,
27 ListMassSubscription
, ListNew
, ListSubscribe
, MemberModeration
,
28 MemberPolicyForm
, MessageAcceptanceForm
)
29 from postorius
.forms
.system
import AddBanForm
30 from postorius
.tests
.utils
import create_mock_list
33 class TestListSubscribe(TestCase
):
35 def test_required_fields_only(self
):
36 user_emails
= ['bob@example.com', 'anne@example.com']
37 form
= ListSubscribe(user_emails
, dict(email
='bob@example.com'))
38 self
.assertTrue(form
.is_valid())
40 def test_email_is_only_from_choices(self
):
41 user_emails
= ['bob@example.com', 'anne@example.com']
42 form
= ListSubscribe(user_emails
, dict(email
='alice@example.com',
43 display_name
='Alice'))
44 self
.assertFalse(form
.is_valid())
45 self
.assertTrue('email' in form
.errors
)
46 self
.assertTrue('Select a valid choice.' in form
.errors
['email'][0])
48 def test_subscribe_works(self
):
49 user_emails
= ['someone@example.com']
50 form
= ListSubscribe(user_emails
,
51 {'email': 'someone@example.com',
52 'display_name': 'Someone'})
53 self
.assertTrue(form
.is_valid())
55 def test_subscribe_fails(self
):
56 user_emails
= ['someone@example.com']
57 form
= ListSubscribe(user_emails
,
58 {'email': 'notaemail',
59 'display_name': 'Someone'})
60 self
.assertFalse(form
.is_valid())
61 self
.assertTrue('email' in form
.errors
.keys())
62 self
.assertEqual(form
.errors
['email'][0],
63 'Select a valid choice.'
64 ' notaemail is not one of the available choices.')
66 def test_subscribe_validates_email(self
):
67 user_emails
= ['something']
68 form
= ListSubscribe(user_emails
,
69 {'email': 'something',
70 'display_name': 'Someone'})
71 self
.assertFalse(form
.is_valid())
72 self
.assertTrue('email' in form
.errors
.keys())
73 self
.assertEqual(form
.errors
['email'][0],
74 'Please enter a valid email address.')
77 class TestChangeSubscription(TestCase
):
79 def test_subscription_changes_only_to_user_addresses(self
):
80 user_emails
= ['one@example.com', 'two@example.com']
81 form
= ChangeSubscriptionForm(user_emails
, {'email': 'abcd@d.com'})
82 self
.assertFalse(form
.is_valid())
83 self
.assertTrue('email' in form
.errors
.keys())
84 self
.assertEqual(form
.errors
['email'][0],
85 'Select a valid choice. '
86 'abcd@d.com is not one of the available choices.')
88 def test_subscription_works(self
):
89 user_emails
= ['one@example.com', 'two@example.com']
90 form
= ChangeSubscriptionForm(user_emails
,
91 {'email': 'two@example.com'})
92 self
.assertTrue(form
.is_valid())
94 def test_subscription_form_labels(self
):
95 user_emails
= ['one@example.com', 'two@example.com']
96 form
= ChangeSubscriptionForm(user_emails
, {})
97 self
.assertTrue(form
.is_valid())
98 self
.assertEqual(form
.fields
['email'].label
, 'Select Email')
100 def test_form_validity(self
):
101 form
= ChangeSubscriptionForm(
102 ['email@example.com', 'john@example.com', 'doe@example.com'],
103 {'email': 'email@example.com'})
104 self
.assertTrue(form
.is_valid())
106 def test_required_fields(self
):
107 # There is no required fields, so empty form should be valid.
108 form
= ChangeSubscriptionForm(
109 ['email@example.com', 'john@example.com', 'doe@example.com'],
111 self
.assertTrue(form
.is_valid())
114 class TestListNew(TestCase
):
116 def test_form_fields_list(self
):
118 ("mailman.most-desirable.org", "mailman.most-desirable.org")]
120 ("legacy-default", 'Ordinary discussion mailing list style.'),
121 ("legacy-announce", 'Announce only mailing list style.')]
122 form
= ListNew(domain_choices
, style_choices
,
124 'mail_host': 'mailman.most-desirable.org',
125 'list_owner': 'contact@mailman.most-desirable.org',
126 'advertised': 'True',
127 'list_style': 'legacy-default',
128 'description': 'The Most Desirable organization'})
129 self
.assertTrue(form
.is_valid(), form
.errors
)
131 def test_form_fields_list_invalid(self
):
133 ("mailman.most-desirable.org", "mailman.most-desirable.org")]
135 ("legacy-default", 'Ordinary discussion mailing list style.'),
136 ("legacy-announce", 'Announce only mailing list style.')]
137 form
= ListNew(domain_choices
, style_choices
,
139 'mail_host': 'mailman.most-desirable.org',
140 'list_owner': 'mailman.most-desirable.org',
141 'advertised': 'abcd',
142 'list_style': 'defg',
143 'description': 'The Most Desirable organization'})
144 self
.assertFalse(form
.is_valid())
145 # Test that all invalid fields are actually checked.
146 for field
in ('list_owner', 'advertised'):
147 self
.assertTrue(field
in form
.errors
)
148 self
.assertTrue('Enter a valid email address.' in
149 form
.errors
['list_owner'])
151 'Select a valid choice. abcd is not one of the available choices.'
152 in form
.errors
['advertised'])
154 def test_form_without_domain_choices(self
):
157 'mail_host': 'mailman.most-desirable.org',
158 'list_owner': 'contact@mailman.most-desirable.org',
159 'advertised': 'True',
160 'description': 'The Most Desirable organization', })
161 # Without domain choices, the form is not going to be valid.
162 self
.assertFalse(form
.is_valid())
163 self
.assertTrue(form
.fields
['mail_host'].help_text
== # noqa: W504
164 'Site admin has not created any domains')
166 def test_listname_validation(self
):
168 ("mailman.most-desirable.org", "mailman.most-desirable.org")]
170 ("legacy-default", 'Ordinary discussion mailing list style.'),
171 ("legacy-announce", 'Announce only mailing list style.')]
172 form
= ListNew(domain_choices
, style_choices
,
174 'mail_host': 'mailman.most-desirable.org',
175 'list_owner': 'mailman.most-desirable.org',
176 'advertised': 'abcd',
177 'description': 'The Most Desirable organization', })
178 self
.assertFalse(form
.is_valid())
179 self
.assertTrue('listname' in form
.errors
)
180 self
.assertTrue('Please enter a valid listname' in
181 form
.errors
['listname'])
183 @unittest.expectedFailure
184 def test_listname_validation_errors_sane(self
):
185 # This test is going to fail right now, but needs to be fixed.
187 ("mailman.most-desirable.org", "mailman.most-desirable.org")],
189 'mail_host': 'mailman.most-desirable.org',
190 'list_owner': 'mailman.most-desirable.org',
191 'advertised': 'abcd',
192 'description': 'The Most Desirable organization', })
193 self
.assertFalse(form
.is_valid())
194 self
.assertTrue('listname' in form
.errors
)
196 'Please enter a valid listname, "@" is not allowed in listname',
197 form
.errors
['listname'])
199 def test_form_fields_order(self
):
201 ("mailman.most-desirable.org", "mailman.most-desirable.org")]
203 ("legacy-default", 'Ordinary discussion mailing list style.'),
204 ("legacy-announce", 'Announce only mailing list style.')]
205 form
= ListNew(domain_choices
, style_choices
,
207 'mail_host': 'mailman.most-desirable.org',
208 'list_owner': 'mailman@most-desirable.org',
209 'list_style': 'legacy-default',
210 'advertised': 'True',
211 'description': 'The Most Desirable organization', })
212 self
.assertTrue(form
.is_valid())
213 # The order of the fields should remain exactly like this.
214 self
.assertEqual(list(form
.fields
),
223 class TestListIdentityForm(TestCase
):
225 def test_not_required_fields(self
):
226 # Only advertised is the required form field.
227 form
= ListIdentityForm({
228 'advertised': 'True',
230 self
.assertTrue(form
.is_valid(), form
.errors
)
232 def test_field_validations(self
):
233 form
= ListIdentityForm({
234 'advertised': 'abcd',
235 'description': 'This is the most desirable organization',
236 'info': 'This is a larger description of this mailing list.',
237 'display_name': 'Most Desirable Mailing List',
238 'subject_prefix': ' [Most Desirable] ',
239 'preferred_language': 'en',
240 'member_roster_visibility': 'public',
242 self
.assertFalse(form
.is_valid())
243 self
.assertTrue('advertised' in form
.errors
)
244 self
.assertEqual(['Select a valid choice. abcd is not one of the available choices.'], # noqa
245 form
.errors
['advertised'])
246 # We shouldn't be removing trailing whitespaces, but we
247 # should remove the leading ones.
248 self
.assertEqual(form
.cleaned_data
['subject_prefix'],
252 class TestListMassSubscription(TestCase
):
254 def test_all_valid_email_formats(self
):
255 form
= ListMassSubscription({
259 John Doe <jdoe@example.com>
260 "John Doe" <jdoe@example.com>
261 jdoe@example.com (John Doe)'''})
262 self
.assertTrue(form
.is_valid())
264 def test_required_fields(self
):
265 form
= ListMassSubscription({'email': ' '})
266 self
.assertFalse(form
.is_valid())
267 self
.assertEqual(['This field is required.'],
268 form
.errors
['emails'])
269 form
= ListMassSubscription({'email': '----'})
270 self
.assertFalse(form
.is_valid())
271 self
.assertEqual(['This field is required.'],
272 form
.errors
['emails'])
275 class TestListMassRemoval(TestCase
):
277 def test_all_valid_formats(self
):
278 form
= ListMassRemoval({
282 John Doe <jdoe@example.com>
283 "John Doe" <jdoe@example.com>
284 jdoe@example.com (John Doe)'''})
285 self
.assertTrue(form
.is_valid())
288 class TestAddBanForm(TestCase
):
290 def test_form_validity(self
):
291 form
= AddBanForm({'email': 'jdoe@example.com'})
292 self
.assertTrue(form
.is_valid())
294 def test_missing_fields_errors(self
):
295 form
= AddBanForm({})
296 self
.assertFalse(form
.is_valid())
297 self
.assertTrue('email' in form
.errors
)
298 self
.assertEqual(form
.errors
['email'],
299 ['Please enter an email address.'])
301 @unittest.expectedFailure
302 def test_invalid_fields_type(self
):
303 # Valid values for email is either a regexp or an email address.
304 # However, this is currently not validated by the form.
305 form
= AddBanForm({'email': 'invalid@'})
306 self
.assertFalse(form
.is_valid())
307 self
.assertTrue('email' in form
.errors
)
308 self
.assertEqual(form
.errors
['email'],
309 ['Please enter a valid email address.'])
312 class TestListHeaderMatchForm(TestCase
):
314 def test_form_validity(self
):
315 # Test by putting only required fields.
316 form
= ListHeaderMatchForm({
318 'pattern': 'value@example.com'})
319 self
.assertTrue(form
.is_valid())
321 form
= ListHeaderMatchForm({
323 'pattern': 'value@example.com',
325 self
.assertTrue(form
.is_valid())
326 # Defer is not a valid action, so validation should fail here.
327 form
= ListHeaderMatchForm({
329 'pattern': 'value@example.com',
331 self
.assertFalse(form
.is_valid())
332 self
.assertTrue('action' in form
.errors
)
335 class TestMemberModeration(TestCase
):
337 def test_moderation_action_validity(self
):
338 form
= MemberModeration({'moderation_action': 'moderation'})
339 self
.assertFalse(form
.is_valid())
340 self
.assertTrue('moderation_action' in form
.errors
)
341 self
.assertEqual(form
.errors
['moderation_action'],
342 ['Select a valid choice. moderation is not one of the available choices.']) # noqa
344 def test_required_fields(self
):
345 form
= MemberModeration({})
346 self
.assertTrue(form
.is_valid())
349 class TestListAutomaticResponsesForm(TestCase
):
351 fields
= ('autorespond_owner', 'autoresponse_owner_text',
352 'autorespond_postings', 'autoresponse_postings_text',
353 'autorespond_requests', 'autoresponse_request_text',
354 'autoresponse_grace_period', 'send_welcome_message',
355 'welcome_message_uri', 'goodbye_message_uri',
356 'admin_immed_notify', 'admin_notify_mchanges')
358 def prepare_formdata(self
, values
):
359 return dict(((key
, val
) for key
, val
in zip(self
.fields
, values
) if val
is not None)) # noqa
361 def test_required_fields_only(self
):
362 values
= ('respond_and_continue', None,
363 'respond_and_continue', None,
364 'respond_and_continue', None,
368 formdata
= self
.prepare_formdata(values
)
369 form
= ListAutomaticResponsesForm(formdata
, mlist
=None)
370 self
.assertTrue(form
.is_valid())
372 def test_all_values(self
):
373 values
= ('respond_and_continue', 'Autorespond text',
374 'respond_and_continue', 'Autorespond text',
375 'respond_and_continue', 'Autorespond text',
377 'http://example.com/welcome_text',
378 'http://example.com/goodbye_message',
380 formdata
= self
.prepare_formdata(values
)
381 form
= ListAutomaticResponsesForm(formdata
, mlist
=None)
383 self
.assertTrue(form
.is_valid())
386 class TestAlterMessageForm(TestCase
):
388 fields
= ('filter_content', 'collapse_alternatives',
389 'convert_html_to_plaintext', 'anonymous_list',
390 'include_rfc2369_headers', 'allow_list_posts',
391 'reply_list_posts', 'reply_to_address',
392 'first_strip_reply_to', 'reply_goes_to_list',
395 def prepare_formdata(self
, values
):
396 return dict(((key
, val
) for key
, val
in zip(self
.fields
, values
) if val
is not None)) # noqa
399 class TestDMARCMitigationsForm(TestCase
):
401 def test_required_fields(self
):
402 # All fields in the form are optional, so an empty form should be
404 form
= DMARCMitigationsForm({}, mlist
=None)
405 self
.assertTrue(form
.is_valid())
407 def test_all_fields(self
):
409 dmarc_mitigate_action
='munge_from',
410 dmarc_mitigate_unconditionally
='True',
411 dmarc_moderation_notice
='This is a moderation notice',
412 dmarc_wrapped_message_text
='This is wrapped message text')
413 form
= DMARCMitigationsForm(formdata
, mlist
=None)
414 self
.assertTrue(form
.is_valid())
417 class TestDigestSettingsForm(TestCase
):
419 def test_required_fields(self
):
420 form
= DigestSettingsForm({}, mlist
=None)
421 self
.assertFalse(form
.is_valid())
422 self
.assertTrue('digest_size_threshold' in form
.errors
)
423 self
.assertEqual(form
.errors
['digest_size_threshold'],
424 ['This field is required.'])
425 form
= DigestSettingsForm({'digest_size_threshold': 40}, mlist
=None)
426 self
.assertTrue(form
.is_valid())
428 def test_all_fields(self
):
430 digests_enabled
='True',
431 digests_send_periodic
='True',
432 digests_volume_frequency
='daily',
433 digest_size_threshold
='10',
435 form
= DigestSettingsForm(formdata
, mlist
=None)
436 self
.assertTrue(form
.is_valid())
439 class TestMessageAcceptanceForm(TestCase
):
441 fields
= ('acceptable_aliases', 'require_explicit_destination',
442 'administrivia', 'default_member_action',
443 'default_nonmember_action', 'max_message_size',
444 'max_num_recipients')
446 def prepare_formdata(self
, values
):
447 return dict(((key
, val
) for key
, val
in zip(self
.fields
, values
) if val
is not None)) # noqa
449 def test_required_fields(self
):
450 # Without any fields, form should not be valid.
451 form
= MessageAcceptanceForm({}, mlist
=None)
452 self
.assertFalse(form
.is_valid())
453 # Now lets try with only required fields.
454 values
= (None, None, None, 'hold', 'hold', 40, 100)
455 form
= MessageAcceptanceForm(self
.prepare_formdata(values
), mlist
=None)
457 self
.assertTrue(form
.is_valid())
459 def test_all_fields(self
):
463 class TestArchiveSettingsForm(TestCase
):
466 self
.mlist
= create_mock_list()
467 archivers
= {'pipermail': True, 'hyperkitty': True}
468 self
.mlist
.archivers
.keys
.side_effect
= archivers
.keys
469 self
.mlist
.archivers
.__getitem
__.side_effect
= archivers
.__getitem
__
470 self
.mlist
.archivers
.__iter
__.side_effect
= archivers
.__iter
__
471 self
.mlist
.archivers
.__contains
__.side_effect
= archivers
.__contains
__
473 def test_required_fields(self
):
474 # First try without any fields.
475 form
= ArchiveSettingsForm({}, mlist
=self
.mlist
)
476 self
.assertFalse(form
.is_valid())
477 self
.assertTrue('archive_policy' in form
.errors
)
478 # Now, with only required fields, this should be a valid form.
479 form
= ArchiveSettingsForm(dict(archive_policy
='public'),
481 self
.assertTrue(form
.is_valid())
483 def test_all_fields(self
):
484 formdata
= dict(archive_policy
='public',
485 archivers
=['pipermail', 'hyperkitty'])
486 form
= ArchiveSettingsForm(formdata
, mlist
=self
.mlist
)
487 self
.assertTrue(form
.is_valid())
489 def test_setup_archivers_populated(self
):
490 formdata
= dict(archive_policy
='public',
491 archivers
=['pipermail', 'hyperkitty'])
492 form
= ArchiveSettingsForm(formdata
, mlist
=self
.mlist
,
493 initial
={'archivers': None})
494 self
.assertTrue(form
.is_valid())
495 self
.assertEqual(form
.initial
['archivers'],
496 ['hyperkitty', 'pipermail'])
499 class TestMemberPolicyForm(TestCase
):
501 def test_required_fields(self
):
502 form
= MemberPolicyForm({}, mlist
=None)
503 self
.assertFalse(form
.is_valid())
504 self
.assertTrue('subscription_policy' in form
.errors
)
505 self
.assertTrue('unsubscription_policy' in form
.errors
)
506 form
= MemberPolicyForm(
507 dict(subscription_policy
='confirm',
508 unsubscription_policy
='confirm'),
510 self
.assertTrue(form
.is_valid())
513 class TestListAnonymousSubscribe(TestCase
):
515 def test_required_fields_only(self
):
516 form
= ListAnonymousSubscribe(dict(email
='bob@exmaple.com'))
517 self
.assertTrue(form
.is_valid())
519 def test_email_is_validated(self
):
520 form
= ListAnonymousSubscribe(dict(email
='invalid'))
521 self
.assertFalse(form
.is_valid())
522 self
.assertTrue('email' in form
.errors
)
523 self
.assertEqual(form
.errors
['email'],
524 ['Please enter a valid email address.'])
526 def test_all_fields(self
):
527 form
= ListAnonymousSubscribe(dict(email
='bob@example.com',
529 self
.assertTrue(form
.is_valid())