kopia lustrzana https://github.com/wagtail/wagtail
Allow to limit access to form submissions (#3016)
Add the filter_form_submissions_for_user hook Thanks @kaedroho for the code review and docs.pull/3016/merge
rodzic
9a57e39cfd
commit
fb93a6d6b9
|
@ -215,7 +215,36 @@ Hooks for building new areas of the admin interface (alongside pages, images, do
|
|||
``register_permissions``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Return a queryset of Permission objects to be shown in the Groups administration area.
|
||||
Return a queryset of ``Permission`` objects to be shown in the Groups administration area.
|
||||
|
||||
|
||||
.. _filter_form_submissions_for_user:
|
||||
|
||||
``filter_form_submissions_for_user``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Allows access to form submissions to be customised on a per-user, per-form basis.
|
||||
|
||||
This hook takes two parameters:
|
||||
- The user attempting to access form submissions
|
||||
- A ``QuerySet`` of form pages
|
||||
|
||||
The hook must return a ``QuerySet`` containing a subset of these form pages which the user is allowed to access the submissions for.
|
||||
|
||||
For example, to prevent non-superusers from accessing form submissions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
|
||||
@hooks.register('filter_form_submissions_for_user')
|
||||
def construct_forms_for_user(user, queryset):
|
||||
if not user.is_superuser:
|
||||
queryset = queryset.none()
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
|
||||
Editor interface
|
||||
|
|
|
@ -15,6 +15,7 @@ from unidecode import unidecode
|
|||
|
||||
from wagtail.wagtailadmin.edit_handlers import FieldPanel
|
||||
from wagtail.wagtailadmin.utils import send_mail
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Orderable, Page, UserPagePermissionsProxy, get_page_models
|
||||
|
||||
from .forms import FormBuilder, WagtailAdminFormPageForm
|
||||
|
@ -140,8 +141,14 @@ def get_forms_for_user(user):
|
|||
"""
|
||||
Return a queryset of form pages that this user is allowed to access the submissions for
|
||||
"""
|
||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
||||
return editable_pages.filter(content_type__in=get_form_types())
|
||||
editable_forms = UserPagePermissionsProxy(user).editable_pages()
|
||||
editable_forms = editable_forms.filter(content_type__in=get_form_types())
|
||||
|
||||
# Apply hooks
|
||||
for fn in hooks.get_hooks('filter_form_submissions_for_user'):
|
||||
editable_forms = fn(user, editable_forms)
|
||||
|
||||
return editable_forms
|
||||
|
||||
|
||||
class AbstractForm(Page):
|
||||
|
|
|
@ -50,7 +50,7 @@ class TestFormResponsesPanel(TestCase):
|
|||
self.assertEqual('', result)
|
||||
|
||||
|
||||
class TestFormsIndex(TestCase):
|
||||
class TestFormsIndex(TestCase, WagtailTestUtils):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
|
@ -133,6 +133,25 @@ class TestFormsIndex(TestCase):
|
|||
# Check that the user can see the form page
|
||||
self.assertIn(self.form_page, response.context['form_pages'])
|
||||
|
||||
def test_cant_see_forms_after_filter_form_submissions_for_user_hook(self):
|
||||
# Hook allows to see forms only to superusers
|
||||
def construct_forms_for_user(user, queryset):
|
||||
if not user.is_superuser:
|
||||
queryset = queryset.none()
|
||||
|
||||
return queryset
|
||||
|
||||
response = self.client.get(reverse('wagtailforms:index'))
|
||||
|
||||
# Check that an user can see the form page
|
||||
self.assertIn(self.form_page, response.context['form_pages'])
|
||||
|
||||
with self.register_hook('filter_form_submissions_for_user', construct_forms_for_user):
|
||||
response = self.client.get(reverse('wagtailforms:index'))
|
||||
|
||||
# Check that an user can't see the form page
|
||||
self.assertNotIn(self.form_page, response.context['form_pages'])
|
||||
|
||||
|
||||
# TODO: Rename to TestFormsSubmissionsList
|
||||
class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
||||
|
@ -185,6 +204,24 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
|||
self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html')
|
||||
self.assertEqual(len(response.context['data_rows']), 2)
|
||||
|
||||
def test_list_submissions_after_filter_form_submissions_for_user_hook(self):
|
||||
# Hook forbids to delete form submissions for everyone
|
||||
def construct_forms_for_user(user, queryset):
|
||||
return queryset.none()
|
||||
|
||||
response = self.client.get(reverse('wagtailforms:list_submissions', args=(self.form_page.id,)))
|
||||
|
||||
# An user can see form submissions without the hook
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html')
|
||||
self.assertEqual(len(response.context['data_rows']), 2)
|
||||
|
||||
with self.register_hook('filter_form_submissions_for_user', construct_forms_for_user):
|
||||
response = self.client.get(reverse('wagtailforms:list_submissions', args=(self.form_page.id,)))
|
||||
|
||||
# An user cant' see form submissions with the hook
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
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'}
|
||||
|
@ -268,6 +305,33 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(data_lines[1], '2013-01-01 12:00:00+00:00,old@example.com,this is a really old message,None\r')
|
||||
self.assertEqual(data_lines[2], '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_after_filter_form_submissions_for_user_hook(self):
|
||||
# Hook forbids to delete form submissions for everyone
|
||||
def construct_forms_for_user(user, queryset):
|
||||
return queryset.none()
|
||||
|
||||
response = self.client.get(
|
||||
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)),
|
||||
{'action': 'CSV'}
|
||||
)
|
||||
|
||||
# An user can export form submissions without the hook
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data_lines = response.content.decode().split("\n")
|
||||
|
||||
self.assertEqual(data_lines[0], 'Submission date,Your email,Your message,Your choices\r')
|
||||
self.assertEqual(data_lines[1], '2013-01-01 12:00:00+00:00,old@example.com,this is a really old message,None\r')
|
||||
self.assertEqual(data_lines[2], '2014-01-01 12:00:00+00:00,new@example.com,this is a fairly new message,None\r')
|
||||
|
||||
with self.register_hook('filter_form_submissions_for_user', construct_forms_for_user):
|
||||
response = self.client.get(
|
||||
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)),
|
||||
{'action': 'CSV'}
|
||||
)
|
||||
|
||||
# An user can't export form submission with the hook
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_list_submissions_csv_export_with_date_from_filtering(self):
|
||||
response = self.client.get(
|
||||
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)),
|
||||
|
@ -365,7 +429,7 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
|||
# TODO: add TestCustomFormsSubmissionsList
|
||||
|
||||
|
||||
class TestDeleteFormSubmission(TestCase):
|
||||
class TestDeleteFormSubmission(TestCase, WagtailTestUtils):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
|
@ -408,6 +472,29 @@ class TestDeleteFormSubmission(TestCase):
|
|||
# Check that the deletion has not happened
|
||||
self.assertEqual(FormSubmission.objects.count(), 2)
|
||||
|
||||
def test_delete_submission_after_filter_form_submissions_for_user_hook(self):
|
||||
# Hook forbids to delete form submissions for everyone
|
||||
def construct_forms_for_user(user, queryset):
|
||||
return queryset.none()
|
||||
|
||||
with self.register_hook('filter_form_submissions_for_user', construct_forms_for_user):
|
||||
response = self.client.post(reverse(
|
||||
'wagtailforms:delete_submission',
|
||||
args=(self.form_page.id, FormSubmission.objects.first().id)
|
||||
))
|
||||
|
||||
# An user can't delete a from submission with the hook
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(FormSubmission.objects.count(), 2)
|
||||
|
||||
# An user can delete a form submission without the hook
|
||||
response = self.client.post(reverse(
|
||||
'wagtailforms:delete_submission',
|
||||
args=(self.form_page.id, FormSubmission.objects.first().id)
|
||||
))
|
||||
self.assertEqual(FormSubmission.objects.count(), 1)
|
||||
self.assertRedirects(response, reverse("wagtailforms:list_submissions", args=(self.form_page.id,)))
|
||||
|
||||
|
||||
# TODO: add TestDeleteCustomFormSubmission
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue