Added hooks for user for create, delete, and edit actions

pull/3981/head
Jonathan Carmack 2017-07-13 20:46:33 -04:00 zatwierdzone przez Matt Westcott
rodzic a28fa5e8c8
commit 7859627a6e
5 zmienionych plików z 265 dodań i 0 usunięć

Wyświetl plik

@ -15,6 +15,7 @@ Changelog
* Moved usage count to the sidebar on the edit page (Kees Hink)
* Explorer menu now reflects customisations to the page listing made via the `construct_explorer_page_queryset` hook and `ModelAdmin.exclude_from_explorer` property (Tim Heap)
* "Choose another image" button changed to "Change image" to avoid ambiguity (Edd Baldry)
* Added hooks `before_create_user`, `after_create_user`, `before_delete_user`, `after_delete_user`, `before_edit_user`, `after_edit_user` (Jon Carmack)
* Fix: Do not remove stopwords when generating slugs from non-ASCII titles, to avoid issues with incorrect word boundaries (Sævar Öfjörð Magnússon)
* Fix: The PostgreSQL search backend now preserves ordering of the `QuerySet` when searching with `order_by_relevance=False` (Bertrand Bordage)
* Fix: Using `modeladmin_register` as a decorator no longer replaces the decorated class with `None` (Tim Heap)

Wyświetl plik

@ -513,6 +513,90 @@ Hooks for customising the way users are directed through the process of creating
return items.append( UserbarPuppyLinkItem() )
Admin workflow
--------------
Hooks for customising the way admins are directed through the process of editing users.
.. _after_create_user:
``after_create_user``
~~~~~~~~~~~~~~~~~~~~~
Do something with a ``User`` object after it has been saved to the database. The callable passed to this hook should take a ``request`` object and a ``user`` object. The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object. By default, Wagtail will instead redirect to the User index page.
.. code-block:: python
from django.http import HttpResponse
from wagtail.wagtailcore import hooks
@hooks.register('after_create_user')
def do_after_page_create(request, user):
return HttpResponse("Congrats on creating a new user!", content_type="text/plain")
.. _before_create_user:
``before_create_user``
~~~~~~~~~~~~~~~~~~~~~~
Called at the beginning of the "create user" view passing in the request.
The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object and skip the rest of the view.
Unlike, ``after_create_user``, this is run both for both ``GET`` and ``POST`` requests.
This can be used to completely override the user editor on a per-view basis:
.. code-block:: python
from wagtail.wagtailcore import hooks
from .models import AwesomePage
from .admin_views import edit_awesome_page
@hooks.register('before_create_user')
def before_create_page(request):
return HttpResponse("A user creation form", content_type="text/plain")
.. _after_delete_user:
``after_delete_user``
~~~~~~~~~~~~~~~~~~~~~
Do something after a ``User`` object is deleted. Uses the same behavior as ``after_create_user``.
.. _before_delete_user:
``before_delete_user``
~~~~~~~~~~~~~~~~~~~~~~
Called at the beginning of the "delete user" view passing in the request and the user object.
Uses the same behavior as ``before_create_user``.
.. _after_edit_user:
``after_edit_user``
~~~~~~~~~~~~~~~~~~~
Do something with a ``User`` object after it has been updated. Uses the same behavior as ``after_create_user``.
.. _before_edit_user:
``before_edit_user``
~~~~~~~~~~~~~~~~~~~~~
Called at the beginning of the "edit user" view passing in the request and the user object.
Uses the same behavior as ``before_create_user``.
Choosers
--------

Wyświetl plik

@ -23,6 +23,7 @@ Other features
* Moved usage count to the sidebar on the edit page (Kees Hink)
* Explorer menu now reflects customisations to the page listing made via the `construct_explorer_page_queryset` hook and `ModelAdmin.exclude_from_explorer` property (Tim Heap)
* "Choose another image" button changed to "Change image" to avoid ambiguity (Edd Baldry)
* Added hooks ``before_create_user``, ``after_create_user``, ``before_delete_user``, ``after_delete_user``, ``before_edit_user``, ``after_edit_user`` (Jon Carmack)
Bug fixes
~~~~~~~~~

Wyświetl plik

@ -5,6 +5,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.core.exceptions import ImproperlyConfigured
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http import HttpRequest, HttpResponse
from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import six
@ -328,6 +329,61 @@ class TestUserCreateView(TestCase, WagtailTestUtils):
self.assertEqual(users.first().email, 'test@user.com')
self.assertFalse(users.first().has_usable_password())
def test_before_create_user_hook(self):
def hook_func(request):
self.assertIsInstance(request, HttpRequest)
return HttpResponse("Overridden!")
with self.register_hook('before_create_user', hook_func):
response = self.client.get(
reverse('wagtailusers_users:add')
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_before_create_user_hook_post(self):
def hook_func(request):
self.assertIsInstance(request, HttpRequest)
return HttpResponse("Overridden!")
with self.register_hook('before_create_user', hook_func):
post_data = {
'username': "testuser",
'email': "testuser@test.com",
'password1': 'password12',
'password2': 'password12',
'first_name': 'test',
'last_name': 'user',
}
response = self.client.post(
reverse('wagtailusers_users:add'),
post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_after_create_user_hook(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertIsInstance(user, get_user_model())
return HttpResponse("Overridden!")
with self.register_hook('after_create_user', hook_func):
post_data = {
'username': "testuser",
'email': "testuser@test.com",
'password1': 'password12',
'password2': 'password12',
'first_name': 'test',
'last_name': 'user',
}
response = self.client.post(
reverse('wagtailusers_users:add'),
post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
class TestUserDeleteView(TestCase, WagtailTestUtils):
def setUp(self):
@ -387,6 +443,45 @@ class TestUserDeleteView(TestCase, WagtailTestUtils):
users = get_user_model().objects.filter(username='testsuperuser')
self.assertEqual(users.count(), 0)
def test_before_delete_user_hook(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.pk, self.test_user.pk)
return HttpResponse("Overridden!")
with self.register_hook('before_delete_user', hook_func):
response = self.client.get(reverse('wagtailusers_users:delete', args=(self.test_user.pk, )))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_before_delete_user_hook_post(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.pk, self.test_user.pk)
return HttpResponse("Overridden!")
with self.register_hook('before_delete_user', hook_func):
response = self.client.post(reverse('wagtailusers_users:delete', args=(self.test_user.pk, )))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_after_delete_user_hook(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.username, self.test_user.username)
return HttpResponse("Overridden!")
with self.register_hook('after_delete_user', hook_func):
response = self.client.post(reverse('wagtailusers_users:delete', args=(self.test_user.pk, )))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
class TestUserDeleteViewForNonSuperuser(TestCase, WagtailTestUtils):
def setUp(self):
@ -703,6 +798,65 @@ class TestUserEditView(TestCase, WagtailTestUtils):
self.assertEqual(user.first_name, 'Edited')
self.assertTrue(user.check_password('password'))
def test_before_edit_user_hook(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.pk, self.test_user.pk)
return HttpResponse("Overridden!")
with self.register_hook('before_edit_user', hook_func):
response = self.client.get(reverse('wagtailusers_users:edit', args=(self.test_user.pk, )))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_before_edit_user_hook_post(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.pk, self.test_user.pk)
return HttpResponse("Overridden!")
with self.register_hook('before_edit_user', hook_func):
post_data = {
'username': "testuser",
'email': "test@user.com",
'first_name': "Edited",
'last_name': "User",
'password1': "password",
'password2': "password",
}
response = self.client.post(
reverse('wagtailusers_users:edit', args=(self.test_user.pk, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
def test_after_edit_user_hook_post(self):
def hook_func(request, user):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(user.pk, self.test_user.pk)
return HttpResponse("Overridden!")
with self.register_hook('after_edit_user', hook_func):
post_data = {
'username': "testuser",
'email': "test@user.com",
'first_name': "Edited",
'last_name': "User",
'password1': "password",
'password2': "password",
}
response = self.client.post(
reverse('wagtailusers_users:edit', args=(self.test_user.pk, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
class TestUserProfileCreation(TestCase, WagtailTestUtils):
def setUp(self):

Wyświetl plik

@ -15,6 +15,7 @@ from wagtail.wagtailadmin import messages
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailadmin.utils import (
any_permission_required, permission_denied, permission_required)
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME
from wagtail.wagtailusers.forms import UserCreationForm, UserEditForm
from wagtail.wagtailusers.utils import user_can_delete_user
@ -122,6 +123,10 @@ def index(request):
@permission_required(add_user_perm)
def create(request):
for fn in hooks.get_hooks('before_create_user'):
result = fn(request)
if hasattr(result, 'status_code'):
return result
if request.method == 'POST':
form = get_user_creation_form()(request.POST, request.FILES)
if form.is_valid():
@ -129,6 +134,10 @@ def create(request):
messages.success(request, _("User '{0}' created.").format(user), buttons=[
messages.button(reverse('wagtailusers_users:edit', args=(user.pk,)), _('Edit'))
])
for fn in hooks.get_hooks('after_create_user'):
result = fn(request, user)
if hasattr(result, 'status_code'):
return result
return redirect('wagtailusers_users:index')
else:
messages.error(request, _("The user could not be created due to errors."))
@ -146,6 +155,10 @@ def edit(request, user_id):
can_delete = user_can_delete_user(request.user, user)
editing_self = request.user == user
for fn in hooks.get_hooks('before_edit_user'):
result = fn(request, user)
if hasattr(result, 'status_code'):
return result
if request.method == 'POST':
form = get_user_edit_form()(request.POST, request.FILES, instance=user, editing_self=editing_self)
if form.is_valid():
@ -153,6 +166,10 @@ def edit(request, user_id):
messages.success(request, _("User '{0}' updated.").format(user), buttons=[
messages.button(reverse('wagtailusers_users:edit', args=(user.pk,)), _('Edit'))
])
for fn in hooks.get_hooks('after_edit_user'):
result = fn(request, user)
if hasattr(result, 'status_code'):
return result
return redirect('wagtailusers_users:index')
else:
messages.error(request, _("The user could not be saved due to errors."))
@ -173,9 +190,17 @@ def delete(request, user_id):
if not user_can_delete_user(request.user, user):
return permission_denied(request)
for fn in hooks.get_hooks('before_delete_user'):
result = fn(request, user)
if hasattr(result, 'status_code'):
return result
if request.method == 'POST':
user.delete()
messages.success(request, _("User '{0}' deleted.").format(user))
for fn in hooks.get_hooks('after_delete_user'):
result = fn(request, user)
if hasattr(result, 'status_code'):
return result
return redirect('wagtailusers_users:index')
return render(request, "wagtailusers/users/confirm_delete.html", {