Add non-field errors to image add/edit forms

pull/6211/head
Matt Westcott 2020-07-01 17:20:32 +01:00
rodzic 8b1699437f
commit 18b8b9d5fc
13 zmienionych plików z 200 dodań i 46 usunięć

Wyświetl plik

@ -11,15 +11,7 @@
{% block furniture %}
<main class="content-wrapper" role="main">
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form method="post" novalidate>
{% csrf_token %}

Wyświetl plik

@ -0,0 +1,9 @@
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

Wyświetl plik

@ -5,15 +5,7 @@
{% trans "Add redirect" as add_red_str %}
{% include "wagtailadmin/shared/header.html" with title=add_red_str icon="redirect" %}
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{% url 'wagtailredirects:add' %}" method="POST" class="nice-padding" novalidate>
{% csrf_token %}

Wyświetl plik

@ -26,15 +26,7 @@
</div>
</div>
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="" method="POST" class="nice-padding" novalidate enctype="multipart/form-data">
{% csrf_token %}

Wyświetl plik

@ -7,15 +7,7 @@
{% trans "Confirm import" as header_subtitle %}
{% include "wagtailadmin/shared/header.html" with title=header_title subtitle=header_subtitle icon="redirect" %}
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{% url 'wagtailredirects:process_import' %}" method="POST" class="nice-padding" novalidate enctype="multipart/form-data">
{% csrf_token %}

Wyświetl plik

@ -5,15 +5,7 @@
{% trans "Editing" as editing_str %}
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=redirect.title icon="redirect" %}
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{% url 'wagtailredirects:edit' redirect.id %}" method="POST" class="nice-padding" novalidate>
{% csrf_token %}

Wyświetl plik

@ -39,6 +39,7 @@
</section>
{% if uploadform %}
<section id="upload" class="{% if uploadform.errors %}active{% endif %} nice-padding">
{% include "wagtailadmin/shared/non_field_errors.html" with form=uploadform %}
<form class="image-upload" action="{% url 'wagtailimages:chooser_upload' %}{% if will_select_format %}?select_format=true{% endif %}" method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}
<ul class="fields">

Wyświetl plik

@ -28,6 +28,8 @@
{% include "wagtailadmin/shared/header.html" with title=add_str icon="image" %}
<div class="nice-padding">
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{% url 'wagtailimages:add' %}" method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}
<ul class="fields">

Wyświetl plik

@ -34,6 +34,7 @@
{% block content %}
{% trans "Editing" as editing_str %}
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=image.title icon="image" %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{% url 'wagtailimages:edit' image.id %}" method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}

Wyświetl plik

@ -1,5 +1,7 @@
{% load i18n %}
{% include "wagtailadmin/shared/non_field_errors.html" %}
<form action="{{ edit_action }}" method="POST" enctype="multipart/form-data" novalidate>
<ul class="fields">
{% csrf_token %}

Wyświetl plik

@ -331,6 +331,31 @@ class TestImageAddView(TestCase, WagtailTestUtils):
image = images.first()
self.assertEqual(image.collection, evil_plans_collection)
@override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
def test_unique_together_validation_error(self):
root_collection = Collection.get_first_root_node()
evil_plans_collection = root_collection.add_child(name="Evil plans")
# another image with a title to collide with
CustomImage.objects.create(
title="Test image",
file=get_test_image_file(),
collection=evil_plans_collection
)
response = self.post({
'title': "Test image",
'file': SimpleUploadedFile('test.png', get_test_image_file().file.getvalue()),
'collection': evil_plans_collection.id,
})
# Shouldn't redirect anywhere
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailimages/images/add.html')
# error message should be output on the page as a non-field error
self.assertContains(response, "Custom image with this Title and Collection already exists.")
class TestImageAddViewWithLimitedCollectionPermissions(TestCase, WagtailTestUtils):
def setUp(self):
@ -617,6 +642,36 @@ class TestImageEditView(TestCase, WagtailTestUtils):
response = self.client.get(reverse('wagtailimages:edit', args=(large_image.id,)))
self.assertContains(response, 'data-original-width="1024"')
@override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
def test_unique_together_validation_error(self):
root_collection = Collection.get_first_root_node()
evil_plans_collection = root_collection.add_child(name="Evil plans")
# Create an image to edit
self.image = CustomImage.objects.create(
title="Test image",
file=get_test_image_file(),
)
# another image with a title to collide with
CustomImage.objects.create(
title="Edited",
file=get_test_image_file(),
collection=evil_plans_collection
)
response = self.post({
'title': "Edited",
'collection': evil_plans_collection.id,
})
# Shouldn't redirect anywhere
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailimages/images/edit.html')
# error message should be output on the page as a non-field error
self.assertContains(response, "Custom image with this Title and Collection already exists.")
@override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
class TestImageEditViewWithCustomImageModel(TestCase, WagtailTestUtils):
@ -972,6 +1027,30 @@ class TestImageChooserUploadView(TestCase, WagtailTestUtils):
# Check that the image was created
self.assertTrue(Image.objects.filter(title="Test image").exists())
@override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
def test_unique_together_validation(self):
root_collection = Collection.get_first_root_node()
evil_plans_collection = root_collection.add_child(name="Evil plans")
# another image with a title to collide with
CustomImage.objects.create(
title="Test image",
file=get_test_image_file(),
collection=evil_plans_collection
)
response = self.client.post(reverse('wagtailimages:chooser_upload'), {
'image-chooser-upload-title': "Test image",
'image-chooser-upload-file': SimpleUploadedFile('test.png', get_test_image_file().file.getvalue()),
'image-chooser-upload-collection': evil_plans_collection.id
})
# Shouldn't redirect anywhere
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailimages/chooser/chooser.html')
# The form should have an error
self.assertContains(response, "Custom image with this Title and Collection already exists.")
class TestImageChooserUploadViewWithLimitedPermissions(TestCase, WagtailTestUtils):
def setUp(self):
@ -1307,7 +1386,7 @@ class TestMultipleImageUploaderWithCustomImageModel(TestCase, WagtailTestUtils):
# Create an image for running tests on
self.image = CustomImage.objects.create(
title="Test image",
title="test-image.png",
file=get_test_image_file(),
)
@ -1381,6 +1460,36 @@ class TestMultipleImageUploaderWithCustomImageModel(TestCase, WagtailTestUtils):
response_json['error_message'], 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.'
)
def test_unique_together_validation_error(self):
"""
If unique_together validation fails, create an UploadedImage and return a form so the
user can fix it
"""
root_collection = Collection.get_first_root_node()
new_collection = root_collection.add_child(name="holiday snaps")
self.image.collection = new_collection
self.image.save()
image_count_before = CustomImage.objects.count()
uploaded_image_count_before = UploadedImage.objects.count()
response = self.client.post(reverse('wagtailimages:add_multiple'), {
'files[]': SimpleUploadedFile('test-image.png', get_test_image_file().file.getvalue()),
'collection': new_collection.id,
}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
image_count_after = CustomImage.objects.count()
uploaded_image_count_after = UploadedImage.objects.count()
# an UploadedImage should have been created now, but not a CustomImage
self.assertEqual(image_count_after, image_count_before)
self.assertEqual(uploaded_image_count_after, uploaded_image_count_before + 1)
# Check response
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
self.assertTemplateUsed(response, 'wagtailimages/multiple/edit_form.html')
def test_edit_post(self):
"""
This tests that a POST request to the edit view edits the image
@ -1410,6 +1519,40 @@ class TestMultipleImageUploaderWithCustomImageModel(TestCase, WagtailTestUtils):
self.assertEqual(new_image.caption, "a boot stamping on a human face, forever")
self.assertIn('footwear', new_image.tags.names())
def test_edit_fails_unique_together_validation(self):
"""
Check that the form returned on failing a unique-together validation error
includes that error message, despite it being a non-field error
"""
root_collection = Collection.get_first_root_node()
new_collection = root_collection.add_child(name="holiday snaps")
# create another image for the edited title to collide with
CustomImage.objects.create(
title="The Eiffel Tower",
file=get_test_image_file(),
collection=new_collection
)
response = self.client.post(reverse('wagtailimages:edit_multiple', args=(self.image.id, )), {
('image-%d-title' % self.image.id): "The Eiffel Tower",
('image-%d-collection' % self.image.id): new_collection.id,
('image-%d-tags' % self.image.id): "",
('image-%d-caption' % self.image.id): "ooh la la",
}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
# Check response
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
self.assertTemplateUsed(response, 'wagtailimages/multiple/edit_form.html')
response_json = json.loads(response.content.decode())
# Check JSON
self.assertEqual(response_json['image_id'], self.image.id)
self.assertFalse(response_json['success'])
# Check that a form error was raised
self.assertIn("Custom image with this Title and Collection already exists.", response_json['form'])
def test_delete_post(self):
"""
This tests that a POST request to the delete view deletes the image

Wyświetl plik

@ -0,0 +1,26 @@
# Generated by Django 2.2.13 on 2020-07-01 14:25
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0046_site_name_remove_null'),
('tests', '0051_tag_verbose_name'),
]
operations = [
migrations.AlterModelOptions(
name='customdocument',
options={},
),
migrations.AlterUniqueTogether(
name='customdocument',
unique_together={('title', 'collection')},
),
migrations.AlterUniqueTogether(
name='customimage',
unique_together={('title', 'collection')},
),
]

Wyświetl plik

@ -923,6 +923,11 @@ class CustomImage(AbstractImage):
'fancy_caption',
)
class Meta:
unique_together = [
('title', 'collection')
]
class CustomRendition(AbstractRendition):
image = models.ForeignKey(CustomImage, related_name='renditions', on_delete=models.CASCADE)
@ -959,6 +964,11 @@ class CustomDocument(AbstractDocument):
'fancy_description'
)
class Meta:
unique_together = [
('title', 'collection')
]
class StreamModel(models.Model):
body = StreamField([