kopia lustrzana https://github.com/wagtail/wagtail
Fix crash when deleting a single snippet using the bulk actions interface (#10447)
Fixes #10441pull/10454/head
rodzic
efb75c0ae3
commit
cc30fd3a13
|
@ -21,6 +21,7 @@ Changelog
|
|||
* Fix: Rectify previous fix for TableBlock becoming uneditable after save (Sage Abdullah)
|
||||
* Fix: Ensure that copying page correctly picks up the latest revision (Matt Westcott)
|
||||
* Fix: Ensure comment buttons always respect `WAGTAILADMIN_COMMENTS_ENABLED` (Thibaud Colas)
|
||||
* Fix: Fix error when deleting a single snippet through the bulk actions interface (Sage Abdullah)
|
||||
* Docs: Update documentation for `log_action` parameter on `RevisionMixin.save_revision` (Christer Jensen)
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ depth: 1
|
|||
* Rectify previous fix for TableBlock becoming uneditable after save (Sage Abdullah)
|
||||
* Ensure that copying page correctly picks up the latest revision (Matt Westcott)
|
||||
* Ensure comment buttons always respect `WAGTAILADMIN_COMMENTS_ENABLED` (Thibaud Colas)
|
||||
* Fix error when deleting a single snippet through the bulk actions interface (Sage Abdullah)
|
||||
|
||||
### Documentation
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from django.contrib.admin.utils import quote
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from wagtail.admin.views.generic import BeforeAfterHookMixin
|
||||
from wagtail.models import ReferenceIndex
|
||||
from wagtail.snippets.bulk_actions.snippet_bulk_action import SnippetBulkAction
|
||||
from wagtail.snippets.permissions import get_permission_name
|
||||
|
||||
|
@ -61,6 +64,25 @@ class DeleteBulkAction(BeforeAfterHookMixin, SnippetBulkAction):
|
|||
).delete()
|
||||
return len(objects), 0
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
# Add usage information to the context only if there is a single item
|
||||
if len(context["items"]) == 1:
|
||||
item_context = context["items"][0]
|
||||
item = item_context["item"]
|
||||
item_context.update(
|
||||
{
|
||||
"usage_count": (
|
||||
ReferenceIndex.get_grouped_references_to(item).count()
|
||||
),
|
||||
"usage_url": reverse(
|
||||
item.snippet_viewset.get_url_name("usage"),
|
||||
args=(quote(item.pk),),
|
||||
),
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
def get_success_message(self, num_parent_objects, num_child_objects):
|
||||
if num_parent_objects == 1:
|
||||
return _("%(model_name)s '%(object)s' deleted.") % {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
{% block titletag %}
|
||||
{% if items|length == 1 %}
|
||||
{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Delete {{ snippet_type_name }}{% endblocktrans %} - {{ items|first }}
|
||||
{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Delete {{ snippet_type_name }}{% endblocktrans %} - {{ items.0.item }}
|
||||
{% else %}
|
||||
{{ items|length }} {{ model_opts.verbose_name_plural|capfirst }}
|
||||
{% endif %}
|
||||
|
@ -22,7 +22,7 @@
|
|||
{% if items %}
|
||||
{% if items|length == 1 %}
|
||||
<div class="usagecount">
|
||||
<a href="{{ items.0.item.usage_url }}">{% blocktrans trimmed count usage_count=items.0.item.get_usage.count %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
||||
<a href="{{ items.0.usage_url }}">{% blocktrans trimmed count usage_count=items.0.usage_count %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
||||
</div>
|
||||
<p>{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Are you sure you want to delete this {{ snippet_type_name }}?{% endblocktrans %}</p>
|
||||
{% else %}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.contrib.admin.utils import quote
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.test import TestCase
|
||||
|
@ -32,11 +33,13 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
)
|
||||
+ "?"
|
||||
)
|
||||
for snippet in self.test_snippets:
|
||||
self.url += f"id={snippet.pk}&"
|
||||
|
||||
def get_url(self, items=()):
|
||||
items = items or self.test_snippets
|
||||
return self.url + "&".join(f"id={item.pk}" for item in items)
|
||||
|
||||
def test_simple(self):
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.get_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtailsnippets/bulk_actions/confirm_bulk_delete.html"
|
||||
|
@ -45,8 +48,32 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
self.assertEqual(response.context["header_icon"], "cog")
|
||||
self.assertContains(response, "icon icon-cog", count=1)
|
||||
|
||||
def test_get_single_delete(self):
|
||||
item = self.test_snippets[0]
|
||||
response = self.client.get(self.get_url(items=(item,)))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtailsnippets/bulk_actions/confirm_bulk_delete.html"
|
||||
)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/shared/header.html")
|
||||
self.assertEqual(response.context["header_icon"], "cog")
|
||||
self.assertContains(response, "icon icon-cog", count=1)
|
||||
self.assertContains(
|
||||
response,
|
||||
"<title>Delete full-featured snippet - Title-1 - Wagtail</title>",
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
reverse(
|
||||
self.snippet_model.snippet_viewset.get_url_name("usage"),
|
||||
args=(quote(item.pk),),
|
||||
),
|
||||
)
|
||||
self.assertContains(response, "Used 0 times")
|
||||
|
||||
def test_bulk_delete(self):
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
|
||||
# Should redirect back to index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
@ -64,7 +91,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
)
|
||||
self.user.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.get_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
html = response.content.decode()
|
||||
|
@ -76,7 +103,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
for snippet in self.test_snippets:
|
||||
self.assertInHTML(f"<li>{snippet.text}</li>", html)
|
||||
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
# User should be redirected back to the index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
|
@ -88,7 +115,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
with self.register_hook(
|
||||
"before_bulk_action", lambda *args: HttpResponse("Overridden!")
|
||||
):
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
@ -113,7 +140,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook("before_bulk_action", hook_func):
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
@ -136,7 +163,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook("after_bulk_action", hook_func):
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
@ -159,7 +186,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook("before_delete_snippet", hook_func):
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
@ -180,7 +207,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook("before_delete_snippet", hook_func):
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
@ -201,7 +228,7 @@ class TestSnippetDeleteView(WagtailTestUtils, TestCase):
|
|||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook("after_delete_snippet", hook_func):
|
||||
response = self.client.post(self.url)
|
||||
response = self.client.post(self.get_url())
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
|
Ładowanie…
Reference in New Issue