Repository: carpentries/amy

Issue:
Server Error when editing community roles
Reported by @ErinBecker at `/workshops/person/<id>/edit/#communityroles` and `/communityroles/role/<another id>/edit/` in production.

Reproduced on test AMY:
```
TypeError at /communityroles/role/25/edit/
the JSON object must be str, bytes or bytearray, not list
Error during template rendering
In template /webapps/test-amy.carpentries.org/repo/amy/templates/bootstrap4/field.html, error at line 39

{% crispy_field field %}
```

Also encountered locally when creating a community role and immediately editing it:
```
Exception Value: | 'NoneType' object is not iterable
/home/eli/amy/amy/communityroles/fields.py, line 20, in get_context

```


Discussion:
Some issue is still present - namely at https://amy.carpentries.org/communityroles/role/<id>/edit/
The remaining server error arises when the form fails validation, as the resulting page is unable to render the custom keys widget (not really sure why when it works on the edit page, but that is the issue). 

The main case where this is occurring is when editing existing community roles, where the relevant `CommunityRoleConfig` has `link_to_award=True`, but the individual community role doesn't have an `award` set. This is tough to replicate in test AMY, as the UI forces you to select an award if it's needed when creating a new `CommunityRole`, but it is common in production AMY, where not all Maintainer/Trainer roles have an associated award, presumably due to this not being required historically.

Fix incoming.

Resolving patch:
diff --git a/amy/communityroles/fields.py b/amy/communityroles/fields.py
--- a/amy/communityroles/fields.py
+++ b/amy/communityroles/fields.py
@@ -63,7 +63,7 @@ def value_from_datadict(
             values = data.getlist(name)
         except AttributeError:
             values = data.get(name, [])
-        return list(zip(self.labels, values))
+        return json.dumps(list(zip(self.labels, values)))
 
     def value_omitted_from_data(
         self, data: QueryDict, files: MultiValueDict, name: str


Test patch:
diff --git a/amy/communityroles/tests/test_community_role_views.py b/amy/communityroles/tests/test_community_role_views.py
--- a/amy/communityroles/tests/test_community_role_views.py
+++ b/amy/communityroles/tests/test_community_role_views.py
@@ -119,6 +119,26 @@ def test_view(self):
         self.assertEqual(page.status_code, 302)  # should redirect to new object
         self.assertRedirects(page, redirect)
 
+    def test_invalid_form_data_returns_page_with_error(self):
+        """
+        Regression test for issue #2336.
+        """
+        # Arrange
+        url = reverse("communityrole_edit", args=[self.community_role.pk])
+        data = self.data.copy()
+        data.pop(
+            "communityrole-award"
+        )  # creates a validation error as link_to_award is True
+
+        # Act
+        page = self.client.post(url, data)
+
+        # Assert
+        self.assertIn(
+            "Award is required with community role Test Role",
+            page.content.decode("utf-8"),
+        )
+
 
 class TestCommunityRoleDeleteView(TestCommunityRoleMixin, TestBase):
     def setUp(self):