diff --git a/wagtail/tests/testapp/fixtures/test.json b/wagtail/tests/testapp/fixtures/test.json index 2e56fbc42a..65ef7afb48 100644 --- a/wagtail/tests/testapp/fixtures/test.json +++ b/wagtail/tests/testapp/fixtures/test.json @@ -23,7 +23,7 @@ "model": "wagtailcore.page", "fields": { "title": "Welcome to the Wagtail test site!", - "numchild": 6, + "numchild": 7, "show_in_menus": false, "live": true, "depth": 2, @@ -440,6 +440,93 @@ } }, +{ + "pk": 17, + "model": "wagtailcore.page", + "fields": { + "title": "Contact us one more time", + "numchild": 0, + "show_in_menus": true, + "live": true, + "depth": 3, + "content_type": ["tests", "formpagewithcustomsubmission"], + "path": "000100010007", + "url_path": "/home/contact-us-one-more-time/", + "slug": "contact-us-one-more-time" + } +}, +{ + "pk": 17, + "model": "tests.formpagewithcustomsubmission", + "fields": { + "to_address": "to@email.com", + "from_address": "from@email.com", + "subject": "The subject" + } +}, +{ + "pk": 1, + "model": "tests.formfieldwithcustomsubmission", + "fields": { + "sort_order": 1, + "label": "Your email", + "field_type": "email", + "required": true, + "choices": "", + "default_value": "", + "help_text": "", + "page": 17 + } +}, +{ + "pk": 2, + "model": "tests.formfieldwithcustomsubmission", + "fields": { + "sort_order": 2, + "label": "Your message", + "field_type": "multiline", + "required": true, + "choices": "", + "default_value": "", + "help_text": "", + "page": 17 + } +}, +{ + "pk": 3, + "model": "tests.formfieldwithcustomsubmission", + "fields": { + "sort_order": 3, + "label": "Your choices", + "field_type": "checkboxes", + "required": false, + "choices": "foo,bar,baz", + "default_value": "", + "help_text": "", + "page": 17 + } +}, +{ + "pk": 1, + "model": "tests.customformpagesubmission", + "fields": { + "form_data": "{\"your-email\": \"old@example.com\", \"your-message\": \"this is a really old message\"}", + "user": 2, + "page": 16, + "submit_time": "2013-01-01T12:00:00.000Z" + } +}, +{ + "pk": 2, + "model": "tests.customformpagesubmission", + "fields": { + "form_data": "{\"your-email\": \"new@example.com\", \"your-message\": \"this is a fairly new message\"}", + "user": 5, + "page": 16, + "submit_time": "2014-01-01T12:00:00.000Z" + } +}, + { "pk": 1, "model": "wagtailcore.site", diff --git a/wagtail/tests/testapp/migrations/0010_auto_20160823_1056.py b/wagtail/tests/testapp/migrations/0010_auto_20160823_1056.py new file mode 100644 index 0000000000..1cf1e17714 --- /dev/null +++ b/wagtail/tests/testapp/migrations/0010_auto_20160823_1056.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-08-23 15:56 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields +import wagtail.wagtailcore.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0029_unicode_slugfield_dj19'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('tests', '0009_defaultstreampage'), + ] + + operations = [ + migrations.CreateModel( + name='CustomFormPageSubmission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('form_data', models.TextField()), + ('submit_time', models.DateTimeField(auto_now_add=True, verbose_name='submit time')), + ], + options={ + 'abstract': False, + 'verbose_name': 'form submission', + }, + ), + migrations.CreateModel( + name='FormFieldWithCustomSubmission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), + ('label', models.CharField(help_text='The label of the form field', max_length=255, verbose_name='label')), + ('field_type', models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Checkboxes'), ('dropdown', 'Drop down'), ('radio', 'Radio buttons'), ('date', 'Date'), ('datetime', 'Date/time')], max_length=16, verbose_name='field type')), + ('required', models.BooleanField(default=True, verbose_name='required')), + ('choices', models.TextField(blank=True, help_text='Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.', verbose_name='choices')), + ('default_value', models.CharField(blank=True, help_text='Default value. Comma separated values supported for checkboxes.', max_length=255, verbose_name='default value')), + ('help_text', models.CharField(blank=True, max_length=255, verbose_name='help text')), + ], + options={ + 'ordering': ['sort_order'], + 'abstract': False, + }, + ), + migrations.CreateModel( + name='FormPageWithCustomSubmission', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ('to_address', models.CharField(blank=True, help_text='Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.', max_length=255, verbose_name='to address')), + ('from_address', models.CharField(blank=True, max_length=255, verbose_name='from address')), + ('subject', models.CharField(blank=True, max_length=255, verbose_name='subject')), + ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)), + ('thank_you_text', wagtail.wagtailcore.fields.RichTextField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.AddField( + model_name='formfieldwithcustomsubmission', + name='page', + field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_form_fields', to='tests.FormPageWithCustomSubmission'), + ), + migrations.AddField( + model_name='customformpagesubmission', + name='page', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Page'), + ), + migrations.AddField( + model_name='customformpagesubmission', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/wagtail/tests/testapp/models.py b/wagtail/tests/testapp/models.py index 0dca5c1754..552c3919a7 100644 --- a/wagtail/tests/testapp/models.py +++ b/wagtail/tests/testapp/models.py @@ -1,13 +1,18 @@ from __future__ import absolute_import, unicode_literals import hashlib +import json import os +from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator +from django.core.serializers.json import DjangoJSONEncoder from django.db import models +from django.shortcuts import render from django.utils.encoding import python_2_unicode_compatible +from django.utils.six import text_type from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel @@ -19,11 +24,12 @@ from wagtail.wagtailadmin.edit_handlers import ( FieldPanel, InlinePanel, MultiFieldPanel, ObjectList, PageChooserPanel, StreamFieldPanel, TabbedInterface) from wagtail.wagtailadmin.forms import WagtailAdminPageForm +from wagtail.wagtailadmin.utils import send_mail from wagtail.wagtailcore.blocks import CharBlock, RichTextBlock from wagtail.wagtailcore.fields import RichTextField, StreamField from wagtail.wagtailcore.models import Orderable, Page, PageManager from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel -from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField +from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField, AbstractFormSubmission from wagtail.wagtailimages.blocks import ImageChooserBlock from wagtail.wagtailimages.edit_handlers import ImageChooserPanel from wagtail.wagtailimages.models import AbstractImage, Image @@ -376,6 +382,90 @@ JadeFormPage.content_panels = [ ] +# FormPage with a custom FormSubmission + +class FormPageWithCustomSubmission(AbstractEmailForm): + """ + This Form page: + * Have custom submission model + * Have custom related_name (see `FormFieldWithCustomSubmission.page`) + * Saves reference to a user + * Doesn't render html form, if submission for current user is present + """ + + intro = RichTextField(blank=True) + thank_you_text = RichTextField(blank=True) + + def get_context(self, request, *args, **kwargs): + context = super(FormPageWithCustomSubmission, self).get_context(request) + context['greeting'] = "hello world" + return context + + def get_form_fields(self): + return self.custom_form_fields.all() + + def get_data_fields(self): + data_fields = [ + ('username', 'Username'), + ] + data_fields += super(FormPageWithCustomSubmission, self).get_data_fields() + + return data_fields + + def get_submission_class(self): + return CustomFormPageSubmission + + def process_form_submission(self, form): + self.get_submission_class().objects.create( + form_data=json.dumps(form.cleaned_data, cls=DjangoJSONEncoder), + page=self, user=form.user + ) + + if self.to_address: + addresses = [x.strip() for x in self.to_address.split(',')] + content = '\n'.join([x[1].label + ': ' + text_type(form.data.get(x[0])) for x in form.fields.items()]) + send_mail(self.subject, content, addresses, self.from_address,) + + def serve(self, request, *args, **kwargs): + if self.get_submission_class().objects.filter(page=self, user__pk=request.user.pk).exists(): + return render( + request, + self.template, + self.get_context(request) + ) + + return super(FormPageWithCustomSubmission, self).serve(request, *args, **kwargs) + + +FormPageWithCustomSubmission.content_panels = [ + FieldPanel('title', classname="full title"), + FieldPanel('intro', classname="full"), + InlinePanel('custom_form_fields', label="Form fields"), + FieldPanel('thank_you_text', classname="full"), + MultiFieldPanel([ + FieldPanel('to_address', classname="full"), + FieldPanel('from_address', classname="full"), + FieldPanel('subject', classname="full"), + ], "Email") +] + + +class FormFieldWithCustomSubmission(AbstractFormField): + page = ParentalKey(FormPageWithCustomSubmission, related_name='custom_form_fields') + + +class CustomFormPageSubmission(AbstractFormSubmission): + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + + def get_data(self): + form_data = super(CustomFormPageSubmission, self).get_data() + form_data.update({ + 'username': self.user.username, + }) + + return form_data + + # Snippets class AdvertPlacement(models.Model): page = ParentalKey('wagtailcore.Page', related_name='advert_placements', on_delete=models.CASCADE) diff --git a/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission.html b/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission.html new file mode 100644 index 0000000000..a7cc07af96 --- /dev/null +++ b/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission.html @@ -0,0 +1,24 @@ +{% extends "tests/base.html" %} +{% load wagtailcore_tags i18n %} + +{% block content %} +

{{ greeting }}

+ + {% if user.is_authenticated and user.is_active or request.is_preview %} + {% if form %} +
+ {{ self.intro|richtext }} +
+
+ {% csrf_token %} + {{ form.as_p }} + +
+ {% else %} +
{% trans 'The form is already filled.' %}
+ {% endif %} + {% else %} +
{% trans 'You must log in first.' %}
+ {% endif %} + +{% endblock %} diff --git a/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission_landing.html b/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission_landing.html new file mode 100644 index 0000000000..562bd68ac1 --- /dev/null +++ b/wagtail/tests/testapp/templates/tests/form_page_with_custom_submission_landing.html @@ -0,0 +1,7 @@ +{% extends "tests/base.html" %} +{% load wagtailcore_tags %} + +{% block content %} +

{{ greeting }}

+ {{ self.thank_you_text|richtext }} +{% endblock %} diff --git a/wagtail/wagtailforms/tests/test_models.py b/wagtail/wagtailforms/tests/test_models.py index 6957fb2c94..065ec66340 100644 --- a/wagtail/wagtailforms/tests/test_models.py +++ b/wagtail/wagtailforms/tests/test_models.py @@ -5,12 +5,12 @@ import json from django.core import mail from django.test import TestCase -from wagtail.tests.testapp.models import FormField, JadeFormPage +from wagtail.tests.testapp.models import CustomFormPageSubmission, FormField, JadeFormPage +from wagtail.tests.utils import WagtailTestUtils from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.models import FormSubmission - -from wagtail.wagtailforms.tests.utils import make_form_page +from wagtail.wagtailforms.tests.utils import make_form_page, make_form_page_with_custom_submission class TestFormSubmission(TestCase): @@ -121,6 +121,173 @@ class TestFormSubmission(TestCase): self.assertIn("Your choices: None", mail.outbox[0].body) +class TestFormWithCustomSubmission(TestCase, WagtailTestUtils): + def setUp(self): + # Create a form page + self.form_page = make_form_page_with_custom_submission() + + self.user = self.login() + + def test_get_form(self): + response = self.client.get('/contact-us/') + + # Check response + self.assertContains(response, """""") + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission_landing.html') + self.assertNotContains(response, '
You must log in first.
', html=True) + self.assertContains(response, '

Boring intro text

', html=True) + + # check that variables defined in get_context are passed through to the template (#1429) + self.assertContains(response, "

hello world

") + + def test_get_form_with_anonymous_user(self): + self.client.logout() + + response = self.client.get('/contact-us/') + + # Check response + self.assertNotContains(response, """""") + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission_landing.html') + self.assertContains(response, '
You must log in first.
', html=True) + self.assertNotContains(response, '

Boring intro text

', html=True) + + # check that variables defined in get_context are passed through to the template (#1429) + self.assertContains(response, "

hello world

") + + def test_post_invalid_form(self): + response = self.client.post('/contact-us/', { + 'your-email': 'bob', + 'your-message': 'hello world', + 'your-choices': '' + }) + + # Check response + self.assertContains(response, "Enter a valid email address.") + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission_landing.html') + + def test_post_valid_form(self): + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {'foo': '', 'bar': '', 'baz': ''} + }) + + # Check response + self.assertContains(response, "Thank you for your patience!") + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission_landing.html') + + # check that variables defined in get_context are passed through to the template (#1429) + self.assertContains(response, "

hello world

") + + # Check that an email was sent + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, "The subject") + self.assertIn("Your message: hello world", mail.outbox[0].body) + self.assertEqual(mail.outbox[0].to, ['to@email.com']) + self.assertEqual(mail.outbox[0].from_email, 'from@email.com') + + # Check that form submission was saved correctly + form_page = Page.objects.get(url_path='/home/contact-us/') + self.assertTrue(CustomFormPageSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists()) + + def test_post_form_twice(self): + # First submission + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {'foo': '', 'bar': '', 'baz': ''} + }) + + # Check response + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission_landing.html') + self.assertContains(response, '

Thank you for your patience!

', html=True) + self.assertNotContains(response, '
The form is already filled.
', html=True) + + # Check that first form submission was saved correctly + submissions_qs = CustomFormPageSubmission.objects.filter(user=self.user, page=self.form_page) + self.assertEqual(submissions_qs.count(), 1) + self.assertTrue(submissions_qs.filter(form_data__contains='hello world').exists()) + + # Second submission + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {'foo': '', 'bar': '', 'baz': ''} + }) + + # Check response + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission_landing.html') + self.assertNotContains(response, '

Thank you for your patience!

', html=True) + self.assertContains(response, '
The form is already filled.
', html=True) + self.assertNotContains(response, '
You must log in first.
', html=True) + self.assertNotContains(response, '

Boring intro text

', html=True) + + # Check that first submission exists and second submission wasn't saved + submissions_qs = CustomFormPageSubmission.objects.filter(user=self.user, page=self.form_page) + self.assertEqual(submissions_qs.count(), 1) + self.assertTrue(submissions_qs.filter(form_data__contains='hello world').exists()) + self.assertFalse(submissions_qs.filter(form_data__contains='hello cruel world').exists()) + + def test_post_unicode_characters(self): + self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'こんにちは、世界', + 'your-choices': {'foo': '', 'bar': '', 'baz': ''} + }) + + # Check the email + self.assertEqual(len(mail.outbox), 1) + self.assertIn("Your message: こんにちは、世界", mail.outbox[0].body) + + # Check the form submission + submission = CustomFormPageSubmission.objects.get() + submission_data = json.loads(submission.form_data) + self.assertEqual(submission_data['your-message'], 'こんにちは、世界') + + def test_post_multiple_values(self): + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {'foo': 'on', 'bar': 'on', 'baz': 'on'} + }) + + # Check response + self.assertContains(response, "Thank you for your patience!") + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission_landing.html') + + # Check that the three checkbox values were saved correctly + form_page = Page.objects.get(url_path='/home/contact-us/') + submission = CustomFormPageSubmission.objects.filter( + page=form_page, form_data__contains='hello world' + ) + self.assertIn("foo", submission[0].form_data) + self.assertIn("bar", submission[0].form_data) + self.assertIn("baz", submission[0].form_data) + + def test_post_blank_checkbox(self): + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {}, + }) + + # Check response + self.assertContains(response, "Thank you for your patience!") + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission_landing.html') + + # Check that the checkbox was serialised in the email correctly + self.assertEqual(len(mail.outbox), 1) + self.assertIn("Your choices: None", mail.outbox[0].body) + + class TestFormSubmissionWithMultipleRecipients(TestCase): def setUp(self): # Create a form page @@ -154,8 +321,44 @@ class TestFormSubmissionWithMultipleRecipients(TestCase): self.assertTrue(FormSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists()) -# TODO: TestFormWithCustomSubmission -# TODO: TestFormSubmissionWithMultipleRecipientsAndWithCustomSubmission +class TestFormSubmissionWithMultipleRecipientsAndWithCustomSubmission(TestCase, WagtailTestUtils): + def setUp(self): + # Create a form page + self.form_page = make_form_page_with_custom_submission( + to_address='to@email.com, another@email.com' + ) + + self.user = self.login() + + def test_post_valid_form(self): + response = self.client.post('/contact-us/', { + 'your-email': 'bob@example.com', + 'your-message': 'hello world', + 'your-choices': {'foo': '', 'bar': '', 'baz': ''} + }) + + # Check response + self.assertContains(response, "Thank you for your patience!") + self.assertTemplateNotUsed(response, 'tests/form_page_with_custom_submission.html') + self.assertTemplateUsed(response, 'tests/form_page_with_custom_submission_landing.html') + + # check that variables defined in get_context are passed through to the template (#1429) + self.assertContains(response, "

hello world

") + + # Check that one email was sent, but to two recipients + self.assertEqual(len(mail.outbox), 1) + + self.assertEqual(mail.outbox[0].subject, "The subject") + self.assertIn("Your message: hello world", mail.outbox[0].body) + self.assertEqual(mail.outbox[0].from_email, 'from@email.com') + self.assertEqual(set(mail.outbox[0].to), {'to@email.com', 'another@email.com'}) + + # Check that form submission was saved correctly + form_page = Page.objects.get(url_path='/home/contact-us/') + self.assertTrue( + CustomFormPageSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists() + ) + class TestIssue798(TestCase): fixtures = ['test.json'] diff --git a/wagtail/wagtailforms/tests/test_views.py b/wagtail/wagtailforms/tests/test_views.py index e776f5c87d..a1dd0036bc 100644 --- a/wagtail/wagtailforms/tests/test_views.py +++ b/wagtail/wagtailforms/tests/test_views.py @@ -3,17 +3,19 @@ from __future__ import absolute_import, unicode_literals import json +from django.contrib.auth import get_user_model from django.core.urlresolvers import reverse from django.test import TestCase -from wagtail.tests.testapp.models import FormField, FormPage +from wagtail.tests.testapp.models import ( + CustomFormPageSubmission, FormField, FormFieldWithCustomSubmission, FormPage) from wagtail.tests.utils import WagtailTestUtils from wagtail.wagtailadmin.edit_handlers import get_form_for_model from wagtail.wagtailadmin.forms import WagtailAdminPageForm from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.edit_handlers import FormSubmissionsPanel from wagtail.wagtailforms.models import FormSubmission -from wagtail.wagtailforms.tests.utils import make_form_page +from wagtail.wagtailforms.tests.utils import make_form_page, make_form_page_with_custom_submission class TestFormResponsesPanel(TestCase): @@ -153,8 +155,7 @@ class TestFormsIndex(TestCase, WagtailTestUtils): self.assertNotIn(self.form_page, response.context['form_pages']) -# TODO: Rename to TestFormsSubmissionsList -class TestFormsSubmissions(TestCase, WagtailTestUtils): +class TestFormsSubmissionsList(TestCase, WagtailTestUtils): def setUp(self): # Create a form page self.form_page = make_form_page() @@ -295,6 +296,36 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils): # Check that we got the last page self.assertEqual(response.context['submissions'].number, response.context['submissions'].paginator.num_pages) + +class TestFormsSubmissionsExport(TestCase, WagtailTestUtils): + def setUp(self): + # Create a form page + self.form_page = make_form_page() + + # Add a couple of form submissions + old_form_submission = FormSubmission.objects.create( + page=self.form_page, + form_data=json.dumps({ + 'your-email': "old@example.com", + 'your-message': "this is a really old message", + }), + ) + old_form_submission.submit_time = '2013-01-01T12:00:00.000Z' + old_form_submission.save() + + new_form_submission = FormSubmission.objects.create( + page=self.form_page, + form_data=json.dumps({ + 'your-email': "new@example.com", + 'your-message': "this is a fairly new message", + }), + ) + new_form_submission.submit_time = '2014-01-01T12:00:00.000Z' + new_form_submission.save() + + # Login + self.login() + def test_list_submissions_csv_export(self): response = self.client.get( reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), @@ -430,7 +461,303 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils): self.assertIn('vim', data_lines[1]) -# TODO: add TestCustomFormsSubmissionsList +class TestCustomFormsSubmissionsExport(TestCase, WagtailTestUtils): + def create_test_user_without_admin(self, username): + return get_user_model().objects.create_user(username=username, password='123') + + def setUp(self): + # Create a form page + self.form_page = make_form_page_with_custom_submission() + + # Add a couple of form submissions + old_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-john'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "old@example.com", + 'your-message': "this is a really old message", + }), + ) + old_form_submission.submit_time = '2013-01-01T12:00:00.000Z' + old_form_submission.save() + + new_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-m1kola'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "new@example.com", + 'your-message': "this is a fairly new message", + }), + ) + new_form_submission.submit_time = '2014-01-01T12:00:00.000Z' + new_form_submission.save() + + # Login + self.login() + + def test_list_submissions_csv_export(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'action': 'CSV'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + data_lines = response.content.decode().split("\n") + + self.assertEqual(data_lines[0], 'Username,Submission date,Your email,Your message,Your choices\r') + self.assertEqual(data_lines[1], + 'user-john,2013-01-01 12:00:00+00:00,old@example.com,this is a really old message,None\r') + self.assertEqual(data_lines[2], + 'user-m1kola,2014-01-01 12:00:00+00:00,new@example.com,this is a fairly new message,None\r') + + def test_list_submissions_csv_export_with_date_from_filtering(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'action': 'CSV', 'date_from': '01/01/2014'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + data_lines = response.content.decode().split("\n") + + self.assertEqual(data_lines[0], 'Username,Submission date,Your email,Your message,Your choices\r') + self.assertEqual(data_lines[1], + 'user-m1kola,2014-01-01 12:00:00+00:00,new@example.com,this is a fairly new message,None\r') + + def test_list_submissions_csv_export_with_date_to_filtering(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'action': 'CSV', 'date_to': '12/31/2013'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + data_lines = response.content.decode().split("\n") + + self.assertEqual(data_lines[0], 'Username,Submission date,Your email,Your message,Your choices\r') + self.assertEqual(data_lines[1], + 'user-john,2013-01-01 12:00:00+00:00,old@example.com,this is a really old message,None\r') + + def test_list_submissions_csv_export_with_range_filtering(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'action': 'CSV', 'date_from': '12/31/2013', 'date_to': '01/02/2014'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + data_lines = response.content.decode().split("\n") + + self.assertEqual(data_lines[0], 'Username,Submission date,Your email,Your message,Your choices\r') + self.assertEqual(data_lines[1], + 'user-m1kola,2014-01-01 12:00:00+00:00,new@example.com,this is a fairly new message,None\r') + + def test_list_submissions_csv_export_with_unicode_in_submission(self): + unicode_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-bob'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "unicode@example.com", + 'your-message': 'こんにちは、世界', + }), + ) + unicode_form_submission.submit_time = '2014-01-02T12:00:00.000Z' + unicode_form_submission.save() + + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'date_from': '01/02/2014', 'action': 'CSV'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + data_line = response.content.decode('utf-8').split("\n")[1] + self.assertIn('こんにちは、世界', data_line) + + def test_list_submissions_csv_export_with_unicode_in_field(self): + FormFieldWithCustomSubmission.objects.create( + page=self.form_page, + sort_order=2, + label="Выберите самую любимую IDE для разработке на Python", + help_text="Вы можете выбрать только один вариант", + field_type='radio', + required=True, + choices='PyCharm,vim,nano', + ) + unicode_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-bob'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "unicode@example.com", + 'your-message': "We don\'t need unicode here", + 'vyberite-samuiu-liubimuiu-ide-dlia-razrabotke-na-python': "vim", + }), + ) + unicode_form_submission.submit_time = '2014-01-02T12:00:00.000Z' + unicode_form_submission.save() + + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'date_from': '01/02/2014', 'action': 'CSV'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + + data_lines = response.content.decode('utf-8').split("\n") + self.assertIn('Выберите самую любимую IDE для разработке на Python', data_lines[0]) + self.assertIn('vim', data_lines[1]) + + +class TestCustomFormsSubmissionsList(TestCase, WagtailTestUtils): + def create_test_user_without_admin(self, username): + return get_user_model().objects.create_user(username=username, password='123') + + def setUp(self): + # Create a form page + self.form_page = make_form_page_with_custom_submission() + + # Add a couple of form submissions + old_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-john'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "old@example.com", + 'your-message': "this is a really old message", + }), + ) + old_form_submission.submit_time = '2013-01-01T12:00:00.000Z' + old_form_submission.save() + + new_form_submission = CustomFormPageSubmission.objects.create( + user=self.create_test_user_without_admin('user-m1kola'), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "new@example.com", + 'your-message': "this is a fairly new message", + }), + ) + new_form_submission.submit_time = '2014-01-01T12:00:00.000Z' + new_form_submission.save() + + # Login + self.login() + + def make_list_submissions(self): + """ + This makes 100 submissions to test pagination on the forms submissions page + """ + for i in range(100): + submission = CustomFormPageSubmission( + user=self.create_test_user_without_admin('generated-username-%s' % i), + page=self.form_page, + form_data=json.dumps({ + 'your-email': "generated-your-email-%s" % i, + 'your-message': "generated-your-message-%s" % i, + }) + ) + submission.save() + + def test_list_submissions(self): + response = self.client.get(reverse('wagtailforms:list_submissions', args=(self.form_page.id,))) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + self.assertEqual(len(response.context['data_rows']), 2) + + # CustomFormPageSubmission have custom field. This field should appear in the listing + self.assertContains(response, 'Username', html=True) + self.assertContains(response, 'user-m1kola', html=True) + self.assertContains(response, 'user-john', html=True) + + def test_list_submissions_filtering_date_from(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), {'date_from': '01/01/2014'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + self.assertEqual(len(response.context['data_rows']), 1) + + # CustomFormPageSubmission have custom field. This field should appear in the listing + self.assertContains(response, 'Username', html=True) + self.assertContains(response, 'user-m1kola', html=True) + + def test_list_submissions_filtering_date_to(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), {'date_to': '12/31/2013'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + self.assertEqual(len(response.context['data_rows']), 1) + + # CustomFormPageSubmission have custom field. This field should appear in the listing + self.assertContains(response, 'Username', html=True) + self.assertContains(response, 'user-john', html=True) + + def test_list_submissions_filtering_range(self): + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'date_from': '12/31/2013', 'date_to': '01/02/2014'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + self.assertEqual(len(response.context['data_rows']), 1) + + # CustomFormPageSubmission have custom field. This field should appear in the listing + self.assertContains(response, 'Username', html=True) + self.assertContains(response, 'user-m1kola', html=True) + + def test_list_submissions_pagination(self): + self.make_list_submissions() + + response = self.client.get(reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got the correct page + self.assertEqual(response.context['submissions'].number, 2) + + # CustomFormPageSubmission have custom field. This field should appear in the listing + self.assertContains(response, 'Username', html=True) + self.assertContains(response, 'generated-username-', count=20) + + def test_list_submissions_pagination_invalid(self): + self.make_list_submissions() + + response = self.client.get( + reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), {'p': 'Hello World!'} + ) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got page one + self.assertEqual(response.context['submissions'].number, 1) + + def test_list_submissions_pagination_out_of_range(self): + self.make_list_submissions() + + response = self.client.get(reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), + {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got the last page + self.assertEqual(response.context['submissions'].number, + response.context['submissions'].paginator.num_pages) class TestDeleteFormSubmission(TestCase, WagtailTestUtils): @@ -500,7 +827,48 @@ class TestDeleteFormSubmission(TestCase, WagtailTestUtils): self.assertRedirects(response, reverse("wagtailforms:list_submissions", args=(self.form_page.id,))) -# TODO: add TestDeleteCustomFormSubmission +class TestDeleteCustomFormSubmission(TestCase): + fixtures = ['test.json'] + + def setUp(self): + self.assertTrue(self.client.login(username='siteeditor', password='password')) + self.form_page = Page.objects.get(url_path='/home/contact-us-one-more-time/') + + def test_delete_submission_show_cofirmation(self): + response = self.client.get(reverse( + 'wagtailforms:delete_submission', + args=(self.form_page.id, CustomFormPageSubmission.objects.first().id) + )) + # Check show confirm page when HTTP method is GET + self.assertTemplateUsed(response, 'wagtailforms/confirm_delete.html') + + # Check that the deletion has not happened with GET request + self.assertEqual(CustomFormPageSubmission.objects.count(), 2) + + def test_delete_submission_with_permissions(self): + response = self.client.post(reverse( + 'wagtailforms:delete_submission', + args=(self.form_page.id, CustomFormPageSubmission.objects.first().id) + )) + + # Check that the submission is gone + self.assertEqual(CustomFormPageSubmission.objects.count(), 1) + # Should be redirected to list of submissions + self.assertRedirects(response, reverse("wagtailforms:list_submissions", args=(self.form_page.id, ))) + + def test_delete_submission_bad_permissions(self): + self.assertTrue(self.client.login(username="eventeditor", password="password")) + + response = self.client.post(reverse( + 'wagtailforms:delete_submission', + args=(self.form_page.id, CustomFormPageSubmission.objects.first().id) + )) + + # Check that the user recieved a 403 response + self.assertEqual(response.status_code, 403) + + # Check that the deletion has not happened + self.assertEqual(CustomFormPageSubmission.objects.count(), 2) class TestIssue585(TestCase): diff --git a/wagtail/wagtailforms/tests/utils.py b/wagtail/wagtailforms/tests/utils.py index 3c14115080..888efe252f 100644 --- a/wagtail/wagtailforms/tests/utils.py +++ b/wagtail/wagtailforms/tests/utils.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals -from wagtail.tests.testapp.models import FormField, FormPage +from wagtail.tests.testapp.models import ( + FormField, FormFieldWithCustomSubmission, + FormPage, FormPageWithCustomSubmission +) from wagtail.wagtailcore.models import Page @@ -40,4 +43,40 @@ def make_form_page(**kwargs): return form_page -# TODO: add make_form_page_with_custom_submission + +def make_form_page_with_custom_submission(**kwargs): + kwargs.setdefault('title', "Contact us") + kwargs.setdefault('intro', "

Boring intro text

") + kwargs.setdefault('thank_you_text', "

Thank you for your patience!

") + kwargs.setdefault('slug', "contact-us") + kwargs.setdefault('to_address', "to@email.com") + kwargs.setdefault('from_address', "from@email.com") + kwargs.setdefault('subject', "The subject") + + home_page = Page.objects.get(url_path='/home/') + form_page = home_page.add_child(instance=FormPageWithCustomSubmission(**kwargs)) + + FormFieldWithCustomSubmission.objects.create( + page=form_page, + sort_order=1, + label="Your email", + field_type='email', + required=True, + ) + FormFieldWithCustomSubmission.objects.create( + page=form_page, + sort_order=2, + label="Your message", + field_type='multiline', + required=True, + ) + FormFieldWithCustomSubmission.objects.create( + page=form_page, + sort_order=3, + label="Your choices", + field_type='checkboxes', + required=False, + choices='foo,bar,baz', + ) + + return form_page