Repository: comic/grand-challenge.org

Issue:
Uploading json file to display set fails but no errors is shown.
**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to a reader study and edit a display set https://grand-challenge.org/reader-studies/cirruscoreweb-release-default-answers/display-sets/
2. Under Regions of interest click on Upload new
3. Click Save
4. Nothing happens, the console and sentry show an error: https://sentry.io/organizations/grand-challenge/issues/3777654067/?project=303639&query=is%3Aunresolved&referrer=issue-stream&statsPeriod=24h


**Expected behavior**
A clear and concise description of what you expected to happen.

Either an error about the json being invalid, or successful upload.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.



Discussion:

Resolving patch:
diff --git a/app/grandchallenge/components/models.py b/app/grandchallenge/components/models.py
--- a/app/grandchallenge/components/models.py
+++ b/app/grandchallenge/components/models.py
@@ -1075,7 +1075,7 @@ def validate_user_upload(self, user_upload):
         if not user_upload.is_completed:
             raise ValidationError("User upload is not completed.")
         if self.interface.is_json_kind:
-            value = user_upload.read_object()
+            value = json.loads(user_upload.read_object())
             self.interface.validate_against_schema(value=value)
         self._user_upload_validated = True
 
diff --git a/app/grandchallenge/reader_studies/forms.py b/app/grandchallenge/reader_studies/forms.py
--- a/app/grandchallenge/reader_studies/forms.py
+++ b/app/grandchallenge/reader_studies/forms.py
@@ -623,7 +623,10 @@ def __init__(
         self.display_set = display_set
 
     def save(self):
-        civ = self.display_set.values.get(interface=self.interface)
+        try:
+            civ = self.display_set.values.get(interface=self.interface)
+        except ObjectDoesNotExist:
+            civ = None
         user_upload = self.cleaned_data["user_upload"]
         on_commit(
             lambda: add_file_to_display_set.apply_async(
@@ -631,7 +634,7 @@ def save(self):
                     "user_upload_pk": str(user_upload.pk),
                     "interface_pk": str(self.interface.pk),
                     "display_set_pk": str(self.display_set.pk),
-                    "civ_pk": str(civ.pk),
+                    "civ_pk": str(civ.pk) if civ else None,
                 }
             )
         )


Test patch:
diff --git a/app/tests/algorithms_tests/test_tasks.py b/app/tests/algorithms_tests/test_tasks.py
--- a/app/tests/algorithms_tests/test_tasks.py
+++ b/app/tests/algorithms_tests/test_tasks.py
@@ -520,18 +520,24 @@ def test_algorithm_input_user_upload(client, settings, component_interfaces):
         user=notification.user
     )
 
-    ci.schema = {}
-    ci.save()
-    civ = ComponentInterfaceValueFactory(interface=ci)
+    upload2 = UserUploadFactory(filename="file.json", creator=creator)
+    presigned_urls2 = upload2.generate_presigned_urls(part_numbers=[1])
+    response2 = put(presigned_urls2["1"], data=b'["foo", "bar"]')
+    upload2.complete_multipart_upload(
+        parts=[{"ETag": response2.headers["ETag"], "PartNumber": 1}]
+    )
+    upload2.save()
+    civ2 = ComponentInterfaceValueFactory(interface=ci)
 
     with capture_on_commit_callbacks(execute=True):
         run_algorithm_job_for_inputs(
             job_pk=job.pk,
             upload_pks=[],
-            user_upload_pks={civ.pk: upload.pk},
+            user_upload_pks={civ2.pk: upload2.pk},
         )
-    civ.refresh_from_db()
-    assert civ.file.read() == b'{"foo": "bar"}'
+    civ2.refresh_from_db()
+    civ2.file.seek(0)
+    assert civ2.file.read() == b'["foo", "bar"]'
 
 
 @pytest.mark.django_db
diff --git a/app/tests/reader_studies_tests/test_forms.py b/app/tests/reader_studies_tests/test_forms.py
--- a/app/tests/reader_studies_tests/test_forms.py
+++ b/app/tests/reader_studies_tests/test_forms.py
@@ -1108,14 +1108,20 @@ def test_file_form(settings):
     assert rs.title in msg
     assert "JSON does not fulfill schema" in msg
 
-    ci.schema = {}
-    ci.save()
     form = FileForm(user=user, display_set=ds, interface=ci)
-    form.cleaned_data = {"user_upload": upload}
+    upload2 = UserUploadFactory(filename="file2.json", creator=user)
+    presigned_urls2 = upload2.generate_presigned_urls(part_numbers=[1])
+    response2 = put(presigned_urls2["1"], data=b'["foo", "bar", "test"]')
+    upload2.complete_multipart_upload(
+        parts=[{"ETag": response2.headers["ETag"], "PartNumber": 1}]
+    )
+    upload2.save()
+    form.cleaned_data = {"user_upload": upload2}
     with capture_on_commit_callbacks(execute=True):
         form.save()
-    civ = ds.values.get(interface=ci)
-    assert civ.file.read() == b'{"foo": "bar"}'
+    civ2 = ds.values.get(interface=ci)
+    civ2.file.seek(0)
+    assert civ2.file.read() == b'["foo", "bar", "test"]'
 
 
 @pytest.mark.django_db