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``
|
``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
|
Editor interface
|
||||||
|
|
|
@ -15,6 +15,7 @@ from unidecode import unidecode
|
||||||
|
|
||||||
from wagtail.wagtailadmin.edit_handlers import FieldPanel
|
from wagtail.wagtailadmin.edit_handlers import FieldPanel
|
||||||
from wagtail.wagtailadmin.utils import send_mail
|
from wagtail.wagtailadmin.utils import send_mail
|
||||||
|
from wagtail.wagtailcore import hooks
|
||||||
from wagtail.wagtailcore.models import Orderable, Page, UserPagePermissionsProxy, get_page_models
|
from wagtail.wagtailcore.models import Orderable, Page, UserPagePermissionsProxy, get_page_models
|
||||||
|
|
||||||
from .forms import FormBuilder, WagtailAdminFormPageForm
|
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
|
Return a queryset of form pages that this user is allowed to access the submissions for
|
||||||
"""
|
"""
|
||||||
editable_pages = UserPagePermissionsProxy(user).editable_pages()
|
editable_forms = UserPagePermissionsProxy(user).editable_pages()
|
||||||
return editable_pages.filter(content_type__in=get_form_types())
|
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):
|
class AbstractForm(Page):
|
||||||
|
|
|
@ -50,7 +50,7 @@ class TestFormResponsesPanel(TestCase):
|
||||||
self.assertEqual('', result)
|
self.assertEqual('', result)
|
||||||
|
|
||||||
|
|
||||||
class TestFormsIndex(TestCase):
|
class TestFormsIndex(TestCase, WagtailTestUtils):
|
||||||
fixtures = ['test.json']
|
fixtures = ['test.json']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -133,6 +133,25 @@ class TestFormsIndex(TestCase):
|
||||||
# Check that the user can see the form page
|
# Check that the user can see the form page
|
||||||
self.assertIn(self.form_page, response.context['form_pages'])
|
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
|
# TODO: Rename to TestFormsSubmissionsList
|
||||||
class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
||||||
|
@ -185,6 +204,24 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
||||||
self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html')
|
self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html')
|
||||||
self.assertEqual(len(response.context['data_rows']), 2)
|
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):
|
def test_list_submissions_filtering_date_from(self):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)), {'date_from': '01/01/2014'}
|
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[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')
|
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):
|
def test_list_submissions_csv_export_with_date_from_filtering(self):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)),
|
reverse('wagtailforms:list_submissions', args=(self.form_page.id,)),
|
||||||
|
@ -365,7 +429,7 @@ class TestFormsSubmissions(TestCase, WagtailTestUtils):
|
||||||
# TODO: add TestCustomFormsSubmissionsList
|
# TODO: add TestCustomFormsSubmissionsList
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteFormSubmission(TestCase):
|
class TestDeleteFormSubmission(TestCase, WagtailTestUtils):
|
||||||
fixtures = ['test.json']
|
fixtures = ['test.json']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -408,6 +472,29 @@ class TestDeleteFormSubmission(TestCase):
|
||||||
# Check that the deletion has not happened
|
# Check that the deletion has not happened
|
||||||
self.assertEqual(FormSubmission.objects.count(), 2)
|
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
|
# TODO: add TestDeleteCustomFormSubmission
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue