Repository: comic/grand-challenge.org

Issue:
Annotation CIV disapears after uploading image CIV
**Describe the bug**
When uploading a Generic Overlay CIV to an archive item that contains one or multiple annotations CIVs (tested with 2D bounding box and point annotations), those annotations disappear.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to an archive item that contains some annotation CIVs
2. Upload an image CIV to the archive item.
3. Refresh to see the annotation CIVs disappeared from the archive item.


**Expected behavior**
The annotation CIVs should remain.

**Screenshots**

https://github.com/comic/grand-challenge.org/assets/2001094/7e54b5c1-4d17-40ae-8ebc-9acf743861cd




Discussion:

Resolving patch:
diff --git a/app/grandchallenge/archives/tasks.py b/app/grandchallenge/archives/tasks.py
--- a/app/grandchallenge/archives/tasks.py
+++ b/app/grandchallenge/archives/tasks.py
@@ -133,7 +133,9 @@ def update_archive_item_values(*, archive_item_pk, civ_pks_to_add):
             ).values_list("pk", flat=True):
                 civ_pks_to_remove.append(civ_pk)
         # for images, check if there are any CIVs with the provided image
-        if civ.interface.is_image_kind:
+        # this is necessary to enable updating the interface
+        # of a given image via the API
+        if civ.interface.is_image_kind and civ.image:
             if instance.values.filter(image=civ.image).exists():
                 for civ_pk in instance.values.filter(
                     image=civ.image


Test patch:
diff --git a/app/tests/archives_tests/test_views.py b/app/tests/archives_tests/test_views.py
--- a/app/tests/archives_tests/test_views.py
+++ b/app/tests/archives_tests/test_views.py
@@ -720,9 +720,14 @@ def test_archive_item_add_image(
     item = ArchiveItemFactory(archive=archive)
     editor = UserFactory()
     archive.add_editor(editor)
-    ci = ComponentInterfaceFactory(
+    ci_img = ComponentInterfaceFactory(
         kind=InterfaceKind.InterfaceKindChoices.IMAGE
     )
+    ci_value = ComponentInterfaceFactory(
+        kind=InterfaceKind.InterfaceKindChoices.BOOL
+    )
+    civ_value = ComponentInterfaceValueFactory(interface=ci_value, value=True)
+    item.values.add(civ_value)
     upload = create_upload_from_file(
         file_path=RESOURCE_PATH / "image10x10x10.mha",
         creator=editor,
@@ -735,17 +740,18 @@ def test_archive_item_add_image(
                 method=client.post,
                 reverse_kwargs={
                     "pk": item.pk,
-                    "interface_slug": ci.slug,
+                    "interface_slug": ci_img.slug,
                     "archive_slug": archive.slug,
                 },
                 user=editor,
                 follow=True,
                 data={
-                    ci.slug: upload.pk,
-                    f"WidgetChoice-{ci.slug}": WidgetChoices.IMAGE_UPLOAD.name,
+                    ci_img.slug: upload.pk,
+                    f"WidgetChoice-{ci_img.slug}": WidgetChoices.IMAGE_UPLOAD.name,
                 },
             )
     assert response.status_code == 200
+    assert item.values.count() == 2
     assert "image10x10x10.mha" == item.values.first().image.name
     old_civ = item.values.first()
 
@@ -757,14 +763,14 @@ def test_archive_item_add_image(
                 method=client.post,
                 reverse_kwargs={
                     "pk": item.pk,
-                    "interface_slug": ci.slug,
+                    "interface_slug": ci_img.slug,
                     "archive_slug": archive.slug,
                 },
                 user=editor,
                 follow=True,
                 data={
-                    ci.slug: old_civ.image.pk,
-                    f"WidgetChoice-{ci.slug}": WidgetChoices.IMAGE_SEARCH.name,
+                    ci_img.slug: old_civ.image.pk,
+                    f"WidgetChoice-{ci_img.slug}": WidgetChoices.IMAGE_SEARCH.name,
                 },
             )
     assert response.status_code == 200
@@ -781,14 +787,14 @@ def test_archive_item_add_image(
                 method=client.post,
                 reverse_kwargs={
                     "pk": item.pk,
-                    "interface_slug": ci.slug,
+                    "interface_slug": ci_img.slug,
                     "archive_slug": archive.slug,
                 },
                 user=editor,
                 follow=True,
                 data={
-                    ci.slug: image.pk,
-                    f"WidgetChoice-{ci.slug}": WidgetChoices.IMAGE_SEARCH.name,
+                    ci_img.slug: image.pk,
+                    f"WidgetChoice-{ci_img.slug}": WidgetChoices.IMAGE_SEARCH.name,
                 },
             )
     assert response.status_code == 200