Repository: wagtail/wagtail

Issue:
KeyError in admin when editing group permissions
There seems to be a bug in the admin when editing permissions for groups (Wagtail 1.4.1).

To reproduce the error:
- Go to Admin -> Settings -> Groups -> Add a Group
- Select "Add a page permission"
- There is a delete button, but clicking it does nothing (problem 1)
- If you do not select a page with "Choose a Page", and proceed to "Save", there is a Python KeyError, for 'page' because there was no page selected (problem 2)

KeyError in admin when editing group permissions
There seems to be a bug in the admin when editing permissions for groups (Wagtail 1.4.1).

To reproduce the error:
- Go to Admin -> Settings -> Groups -> Add a Group
- Select "Add a page permission"
- There is a delete button, but clicking it does nothing (problem 1)
- If you do not select a page with "Choose a Page", and proceed to "Save", there is a Python KeyError, for 'page' because there was no page selected (problem 2)



Discussion:
Problem 2 confirmed on Wagtail 1.4.3. The delete button is working fine for me though...

Problem 2 confirmed on Wagtail 1.4.3. The delete button is working fine for me though...


Resolving patch:
diff --git a/wagtail/wagtailadmin/forms.py b/wagtail/wagtailadmin/forms.py
--- a/wagtail/wagtailadmin/forms.py
+++ b/wagtail/wagtailadmin/forms.py
@@ -418,7 +418,9 @@ def clean(self):
         collections = [
             form.cleaned_data['collection']
             for form in self.forms
-            if form not in self.deleted_forms
+            # need to check for presence of 'collection' in cleaned_data,
+            # because a completely blank form passes validation
+            if form not in self.deleted_forms and 'collection' in form.cleaned_data
         ]
         if len(set(collections)) != len(collections):
             # collections list contains duplicates
@@ -435,7 +437,10 @@ def save(self):
             )
 
         # get a set of (collection, permission) tuples for all ticked permissions
-        forms_to_save = [form for form in self.forms if form not in self.deleted_forms]
+        forms_to_save = [
+            form for form in self.forms
+            if form not in self.deleted_forms and 'collection' in form.cleaned_data
+        ]
 
         final_permission_records = set()
         for form in forms_to_save:
diff --git a/wagtail/wagtailusers/forms.py b/wagtail/wagtailusers/forms.py
--- a/wagtail/wagtailusers/forms.py
+++ b/wagtail/wagtailusers/forms.py
@@ -295,7 +295,9 @@ def clean(self):
         pages = [
             form.cleaned_data['page']
             for form in self.forms
-            if form not in self.deleted_forms
+            # need to check for presence of 'page' in cleaned_data,
+            # because a completely blank form passes validation
+            if form not in self.deleted_forms and 'page' in form.cleaned_data
         ]
         if len(set(pages)) != len(pages):
             # pages list contains duplicates
@@ -309,7 +311,10 @@ def save(self):
             )
 
         # get a set of (page, permission_type) tuples for all ticked permissions
-        forms_to_save = [form for form in self.forms if form not in self.deleted_forms]
+        forms_to_save = [
+            form for form in self.forms
+            if form not in self.deleted_forms and 'page' in form.cleaned_data
+        ]
 
         final_permission_records = set()
         for form in forms_to_save:


Test patch:
diff --git a/wagtail/wagtailusers/tests.py b/wagtail/wagtailusers/tests.py
--- a/wagtail/wagtailusers/tests.py
+++ b/wagtail/wagtailusers/tests.py
@@ -311,6 +311,26 @@ def test_duplicate_document_permissions_error(self):
             )
         )
 
+    def test_can_submit_blank_permission_form(self):
+        # the formsets for page / collection permissions should gracefully
+        # handle (and ignore) forms that have been left entirely blank
+        response = self.post({
+            'name': "test group",
+            'page_permissions-0-page': [''],
+            'page_permissions-TOTAL_FORMS': ['1'],
+            'document_permissions-0-collection': [''],
+            'document_permissions-TOTAL_FORMS': ['1'],
+        })
+
+        self.assertRedirects(response, reverse('wagtailusers_groups:index'))
+        # The test group now exists, with no page / document permissions
+        new_group = Group.objects.get(name='test group')
+        self.assertEqual(new_group.page_permissions.all().count(), 0)
+        self.assertEqual(
+            new_group.collection_permissions.filter(permission=self.add_doc_permission).count(),
+            0
+        )
+
 
 class TestGroupEditView(TestCase, WagtailTestUtils):
     def setUp(self):