Repository: comic/grand-challenge.org

Issue:
Add command to migrate case text
With the new reader studies the case text format changed. We either need to update it for users or find a way to maintain the existing API.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/reader_studies/models.py b/app/grandchallenge/reader_studies/models.py
--- a/app/grandchallenge/reader_studies/models.py
+++ b/app/grandchallenge/reader_studies/models.py
@@ -518,11 +518,7 @@ def help_text(self):
     @property
     def cleaned_case_text(self):
         if self.use_display_sets:
-            return {
-                str(ds.pk): md2html(self.case_text[str(ds.pk)])
-                for ds in self.display_sets.all()
-                if str(ds.pk) in self.case_text
-            }
+            return {}
         else:
             study_images = {im.name: im.api_url for im in self.images.all()}
             return {
@@ -1149,6 +1145,17 @@ def api_url(self):
             "api:reader-studies-display-set-detail", kwargs={"pk": self.pk}
         )
 
+    @property
+    def description(self):
+        case_text = self.reader_study.case_text
+        return "".join(
+            [
+                md2html(case_text[val.image.name])
+                for val in self.values.filter(image__isnull=False)
+                if val.image.name in case_text
+            ]
+        )
+
 
 class AnswerType(models.TextChoices):
     # WARNING: Do not change the display text, these are used in the front end
diff --git a/app/grandchallenge/reader_studies/serializers.py b/app/grandchallenge/reader_studies/serializers.py
--- a/app/grandchallenge/reader_studies/serializers.py
+++ b/app/grandchallenge/reader_studies/serializers.py
@@ -84,6 +84,7 @@ class Meta:
             "api_url",
             "hanging_protocol",
             "view_content",
+            "description",
         )
 
 
diff --git a/app/grandchallenge/reader_studies/views.py b/app/grandchallenge/reader_studies/views.py
--- a/app/grandchallenge/reader_studies/views.py
+++ b/app/grandchallenge/reader_studies/views.py
@@ -866,7 +866,8 @@ def get_context_data(self, **kwargs):
 class ReaderStudyViewSet(ReadOnlyModelViewSet):
     serializer_class = ReaderStudySerializer
     queryset = ReaderStudy.objects.all().prefetch_related(
-        "images", "questions__options"
+        "images",
+        "questions__options",
     )
     permission_classes = [DjangoObjectPermissions]
     filter_backends = [DjangoFilterBackend, ObjectPermissionsFilter]
@@ -1070,8 +1071,10 @@ def destroy(self, request, *args, **kwargs):
         return super().destroy(request, *args, **kwargs)
 
     def get_queryset(self):
-        queryset = DisplaySet.objects.all().select_related(
-            "reader_study__hanging_protocol"
+        queryset = (
+            DisplaySet.objects.all()
+            .select_related("reader_study__hanging_protocol")
+            .prefetch_related("values__image")
         )
         unanswered_by_user = self.request.query_params.get(
             "unanswered_by_user"


Test patch:
diff --git a/app/tests/reader_studies_tests/test_models.py b/app/tests/reader_studies_tests/test_models.py
--- a/app/tests/reader_studies_tests/test_models.py
+++ b/app/tests/reader_studies_tests/test_models.py
@@ -480,3 +480,25 @@ def test_display_set_order():
 
     ds = DisplaySetFactory(reader_study=rs)
     assert ds.order == 20
+
+
+@pytest.mark.django_db
+def test_display_set_description():
+    rs = ReaderStudyFactory()
+    reader = UserFactory()
+    rs.add_reader(reader)
+    images = [ImageFactory() for _ in range(6)]
+    ci = ComponentInterface.objects.get(slug="generic-medical-image")
+    result = {}
+    for image in images:
+        ds = DisplaySetFactory(reader_study=rs)
+        result[ds.pk] = f"<p>{str(image.pk)}</p>"
+        civ = ComponentInterfaceValueFactory(interface=ci, image=image)
+        ds.values.add(civ)
+
+    rs.case_text = {im.name: str(im.pk) for im in images}
+    rs.case_text["no_image"] = "not an image"
+    rs.save()
+
+    for ds in rs.display_sets.all():
+        assert ds.description == result[ds.pk]