kopia lustrzana https://github.com/wagtail/wagtail
Add before_{create,edit,delete}_snippet hooks
rodzic
873160dd9a
commit
f3f932d2e5
|
@ -4,6 +4,7 @@ Changelog
|
|||
2.11 (xx.xx.xxxx) - IN DEVELOPMENT
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Add `before_edit_snippet`, `before_create_snippet` and `before_delete_snippet` hooks and documentation (Karl Hobley. Sponsored by the Mozilla Foundation)
|
||||
|
||||
2.10 (xx.xx.xxxx) - IN DEVELOPMENT
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -1016,6 +1016,24 @@ Hooks for working with registered Snippets.
|
|||
def after_snippet_update(request, instance):
|
||||
return HttpResponse(f"Congrats on editing a snippet with id {instance.pk}", content_type="text/plain")
|
||||
|
||||
.. _before_edit_snippet:
|
||||
|
||||
``before_edit_snippet``
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called at the beginning of the edit snippet view. The callable passed into the hook will receive the model instance, the request object. If the callable returns an ``HttpResponse``, that response will be returned immediately to the user, and Wagtail will not proceed to call ``redirect()`` to the listing view.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
from wagtail.core import hooks
|
||||
|
||||
@hooks.register('before_edit_snippet')
|
||||
def block_snippet_edit(request, instance):
|
||||
if isinstance(instance, RestrictedSnippet) and instance.prevent_edit:
|
||||
return HttpResponse("Sorry, you can't edit this snippet", content_type="text/plain")
|
||||
|
||||
.. _after_create_snippet:
|
||||
|
||||
``after_create_snippet``
|
||||
|
@ -1025,6 +1043,13 @@ Hooks for working with registered Snippets.
|
|||
``after_edit_snippet`` work in identical ways. The only difference is where
|
||||
the hook is called.
|
||||
|
||||
.. _before_create_snippet:
|
||||
|
||||
``before_create_snippet``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called at the beginning of the create snippet view. Works in a similar way to `before_edit_snippet` except the model is passed as an argument instead of an instance.
|
||||
|
||||
.. _after_delete_snippet:
|
||||
|
||||
``after_delete_snippet``
|
||||
|
@ -1044,6 +1069,29 @@ Hooks for working with registered Snippets.
|
|||
total = len(instances)
|
||||
return HttpResponse(f"{total} snippets have been deleted", content_type="text/plain")
|
||||
|
||||
.. _before_delete_snippet:
|
||||
|
||||
``before_delete_snippet``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called at the beginning of the delete snippet view. The callable passed into the hook will receive the model instance(s) as a queryset along with the request object. If the callable returns an ``HttpResponse``, that response will be returned immediately to the user, and Wagtail will not proceed to call ``redirect()`` to the listing view.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
from wagtail.core import hooks
|
||||
|
||||
@hooks.register('before_delete_snippet')
|
||||
def before_snippet_delete(request, instances):
|
||||
# "instances" is a QuerySet
|
||||
total = len(instances)
|
||||
|
||||
if request.method == 'POST':
|
||||
# Override the deletion behaviour
|
||||
instances.delete()
|
||||
|
||||
return HttpResponse(f"{total} snippets have been deleted", content_type="text/plain")
|
||||
|
||||
Audit log
|
||||
---------
|
||||
|
|
|
@ -13,7 +13,7 @@ What's new
|
|||
Other features
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* Add ``before_edit_snippet``, ``before_create_snippet`` and ``before_delete_snippet`` hooks and documentation (Karl Hobley. Sponsored by the Mozilla Foundation)
|
||||
|
||||
|
||||
Bug fixes
|
||||
|
|
|
@ -228,6 +228,37 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
|
|||
snippet = FileUploadSnippet.objects.get()
|
||||
self.assertEqual(snippet.file.read(), b"Uploaded file")
|
||||
|
||||
def test_before_create_snippet_hook_get(self):
|
||||
def hook_func(request, model):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertEqual(model, Advert)
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_create_snippet', hook_func):
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
def test_before_create_snippet_hook_post(self):
|
||||
def hook_func(request, model):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertEqual(model, Advert)
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_create_snippet', hook_func):
|
||||
post_data = {
|
||||
'text': 'Hook test',
|
||||
'url': 'http://www.example.com/'
|
||||
}
|
||||
response = self.post(post_data=post_data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted before advert was created
|
||||
self.assertFalse(Advert.objects.exists())
|
||||
|
||||
def test_after_create_snippet_hook(self):
|
||||
def hook_func(request, instance):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
|
@ -245,6 +276,9 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted after advert was created
|
||||
self.assertTrue(Advert.objects.exists())
|
||||
|
||||
|
||||
class BaseTestSnippetEditView(TestCase, WagtailTestUtils):
|
||||
|
||||
|
@ -318,6 +352,38 @@ class TestSnippetEditView(BaseTestSnippetEditView):
|
|||
list(snippet.tags.order_by('name')),
|
||||
expected_tags)
|
||||
|
||||
def test_before_edit_snippet_hook_get(self):
|
||||
|
||||
def hook_func(request, instance):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertEqual(instance.text, 'test_advert')
|
||||
self.assertEqual(instance.url, 'http://www.example.com')
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_edit_snippet', hook_func):
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
def test_before_edit_snippet_hook_post(self):
|
||||
|
||||
def hook_func(request, instance):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertEqual(instance.text, 'test_advert')
|
||||
self.assertEqual(instance.url, 'http://www.example.com')
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_edit_snippet', hook_func):
|
||||
response = self.post(post_data={'text': 'Edited and runs hook',
|
||||
'url': 'http://www.example.com/hook-enabled-edited'})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted before advert was updated
|
||||
self.assertEqual(Advert.objects.get().text, "test_advert")
|
||||
|
||||
def test_after_edit_snippet_hook(self):
|
||||
|
||||
def hook_func(request, instance):
|
||||
|
@ -333,6 +399,9 @@ class TestSnippetEditView(BaseTestSnippetEditView):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted after advert was updated
|
||||
self.assertEqual(Advert.objects.get().text, "Edited and runs hook")
|
||||
|
||||
|
||||
class TestEditTabbedSnippet(BaseTestSnippetEditView):
|
||||
|
||||
|
@ -402,6 +471,45 @@ class TestSnippetDelete(TestCase, WagtailTestUtils):
|
|||
self.assertContains(response, 'Used 2 times')
|
||||
self.assertContains(response, self.test_snippet.usage_url())
|
||||
|
||||
def test_before_delete_snippet_hook_get(self):
|
||||
advert = Advert.objects.create(
|
||||
url='http://www.example.com/',
|
||||
text='Test hook',
|
||||
)
|
||||
|
||||
def hook_func(request, instances):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertQuerysetEqual(instances, ["<Advert: Test hook>"])
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_delete_snippet', hook_func):
|
||||
response = self.client.get(reverse('wagtailsnippets:delete', args=['tests', 'advert', quote(advert.pk)]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
def test_before_delete_snippet_hook_post(self):
|
||||
advert = Advert.objects.create(
|
||||
url='http://www.example.com/',
|
||||
text='Test hook',
|
||||
)
|
||||
|
||||
def hook_func(request, instances):
|
||||
self.assertIsInstance(request, HttpRequest)
|
||||
self.assertQuerysetEqual(instances, ["<Advert: Test hook>"])
|
||||
return HttpResponse("Overridden!")
|
||||
|
||||
with self.register_hook('before_delete_snippet', hook_func):
|
||||
response = self.client.post(
|
||||
reverse('wagtailsnippets:delete', args=('tests', 'advert', quote(advert.pk), ))
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted before advert was deleted
|
||||
self.assertTrue(Advert.objects.filter(pk=advert.pk).exists())
|
||||
|
||||
def test_after_delete_snippet_hook(self):
|
||||
advert = Advert.objects.create(
|
||||
url='http://www.example.com/',
|
||||
|
@ -421,6 +529,9 @@ class TestSnippetDelete(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, b"Overridden!")
|
||||
|
||||
# Request intercepted after advert was deleted
|
||||
self.assertFalse(Advert.objects.filter(pk=advert.pk).exists())
|
||||
|
||||
|
||||
class TestSnippetDeleteMultipleWithOne(TestCase, WagtailTestUtils):
|
||||
# test deletion of one snippet using the delete-multiple URL
|
||||
|
|
|
@ -134,6 +134,11 @@ def create(request, app_label, model_name):
|
|||
if not request.user.has_perm(permission):
|
||||
return permission_denied(request)
|
||||
|
||||
for fn in hooks.get_hooks('before_create_snippet'):
|
||||
result = fn(request, model)
|
||||
if hasattr(result, 'status_code'):
|
||||
return result
|
||||
|
||||
instance = model()
|
||||
edit_handler = get_snippet_edit_handler(model)
|
||||
edit_handler = edit_handler.bind_to(request=request)
|
||||
|
@ -188,6 +193,12 @@ def edit(request, app_label, model_name, pk):
|
|||
return permission_denied(request)
|
||||
|
||||
instance = get_object_or_404(model, pk=unquote(pk))
|
||||
|
||||
for fn in hooks.get_hooks('before_edit_snippet'):
|
||||
result = fn(request, instance)
|
||||
if hasattr(result, 'status_code'):
|
||||
return result
|
||||
|
||||
edit_handler = get_snippet_edit_handler(model)
|
||||
edit_handler = edit_handler.bind_to(instance=instance, request=request)
|
||||
form_class = edit_handler.get_form_class()
|
||||
|
@ -247,6 +258,11 @@ def delete(request, app_label, model_name, pk=None):
|
|||
ids = request.GET.getlist('id')
|
||||
instances = model.objects.filter(pk__in=ids)
|
||||
|
||||
for fn in hooks.get_hooks('before_delete_snippet'):
|
||||
result = fn(request, instances)
|
||||
if hasattr(result, 'status_code'):
|
||||
return result
|
||||
|
||||
count = len(instances)
|
||||
|
||||
if request.method == 'POST':
|
||||
|
|
Ładowanie…
Reference in New Issue