Repository: comic/grand-challenge.org

Issue:
Restrict retina import functions
Soon, external people want to be able to import certain images into the retina workstation. Therefore, they need access to `retina_importer` endpoints. Currently, there are several endpoints that were created for importing data from the old workstation (annotations) and to correct accidental mistakes in the current images (element spacing header in mhd files). These endpoints should be removed.
The only endpoints that should remain are for uploading of images and related studies/patients/archives.


Discussion:

Resolving patch:
diff --git a/app/grandchallenge/retina_importers/serializers.py b/app/grandchallenge/retina_importers/serializers.py
deleted file mode 100644
--- a/app/grandchallenge/retina_importers/serializers.py
+++ /dev/null
@@ -1,126 +0,0 @@
-from rest_framework import serializers
-
-
-class AbstractUploadSerializer(serializers.Serializer):
-    archive_identifier = serializers.CharField(max_length=255, required=True)
-    patient_identifier = serializers.CharField(max_length=255, required=True)
-    user_identifier = serializers.CharField(max_length=150, required=True)
-    datetime = serializers.DateTimeField()
-    data = serializers.ListField(child=serializers.DictField())
-
-    # Functon for validation coordinate values
-    # Prefixed with do_ to disable recognition as a validate field function by serializer
-    def do_validate_coordinates(self, data):
-        # Validate if data is in the form of [x(float), y(float)]
-        valid = True
-        if not isinstance(data, list) or len(data) != 2:
-            valid = False
-        else:
-            for point in data:
-                if not isinstance(point, float) and not isinstance(point, int):
-                    valid = False
-
-        if not valid:
-            raise serializers.ValidationError(
-                "Coordinates in {} are not valid. Invalid value: {}".format(
-                    self.__class__.__name__, data
-                )
-            )
-
-    @staticmethod
-    def do_validate_as_charfield(value, name, max_length=255, required=True):
-        # Check if value is valid charfield
-        if required and not value:
-            raise serializers.ValidationError(
-                "{} cannot be empty".format(name)
-            )
-
-        if not isinstance(value, str):
-            raise serializers.ValidationError(
-                "{} must be a string".format(name)
-            )
-
-        if len(value) > max_length:
-            raise serializers.ValidationError(
-                "{} exceeds max length of {} characters".format(
-                    name, max_length
-                )
-            )
-
-    def validate_data(self, value):
-        for dict_obj in value:
-            for key, val in dict_obj.items():
-                if key in (
-                    "series_identifier",
-                    "image_identifier",
-                    "study_identifier",
-                ):
-                    self.do_validate_as_charfield(val, key)
-
-        return value
-
-    class Meta:
-        abstract = True
-        fields = (
-            "archive_identifier",
-            "patient_identifier",
-            "user_identifier",
-            "datetime",
-            "data",
-        )
-
-
-class UploadLandmarkAnnotationSetSerializer(AbstractUploadSerializer):
-    def validate(self, data):
-        for annotation in data["data"]:
-            for point in annotation["landmarks"]:
-                self.do_validate_coordinates(point)
-
-        return data
-
-
-class UploadETDRSGridAnnotationSerializer(AbstractUploadSerializer):
-    def validate(self, data):
-        # check if etdrs fovea and optic disk contain valid coordinates
-        for etdrs_grid in data["data"]:
-            for coordinates_type in ("fovea", "optic_disk"):
-                self.do_validate_coordinates(etdrs_grid[coordinates_type])
-        return data
-
-
-class UploadMeasurementAnnotationSerializer(AbstractUploadSerializer):
-    def validate(self, data):
-        # check if start and end coordinates contain valid coordinates
-        for measurement in data["data"]:
-            for pos_type in ("start_voxel", "end_voxel"):
-                self.do_validate_coordinates(measurement[pos_type])
-        return data
-
-
-class UploadBooleanClassificationAnnotationSerializer(
-    AbstractUploadSerializer
-):
-    def validate(self, data):
-        for annotation in data["data"]:
-            if not isinstance(annotation["value"], bool):
-                raise serializers.ValidationError(
-                    "Value in BooleanClassificationAnnotation is not a boolean"
-                )
-            if not isinstance(annotation["name"], str):
-                raise serializers.ValidationError(
-                    "Name in BooleanClassificationAnnotation is not a string"
-                )
-        return data
-
-
-class UploadPolygonAnnotationSetSerializer(AbstractUploadSerializer):
-    def validate(self, data):
-        for annotation in data["data"]:
-            self.do_validate_as_charfield(
-                annotation["name"], "PolygonAnnotationSet.name"
-            )
-
-            for ga_polygon in annotation["value"]:
-                for coordinate in ga_polygon:
-                    self.do_validate_coordinates(coordinate)
-        return data
diff --git a/app/grandchallenge/retina_importers/urls.py b/app/grandchallenge/retina_importers/urls.py
--- a/app/grandchallenge/retina_importers/urls.py
+++ b/app/grandchallenge/retina_importers/urls.py
@@ -6,34 +6,4 @@
 urlpatterns = [
     path("check_image/", views.CheckImage.as_view(), name="check-image"),
     path("upload_image/", views.UploadImage.as_view(), name="upload-image"),
-    path(
-        "upload_image_registration_landmarks/",
-        views.UploadLandmarkAnnotationSet.as_view(),
-        name="upload-image-registration-landmarks",
-    ),
-    path(
-        "upload_etdrs_grid_annotation/",
-        views.UploadETDRSGridAnnotation.as_view(),
-        name="upload-etdrs-grid-annotation",
-    ),
-    path(
-        "upload_measurement_annotation/",
-        views.UploadMeasurementAnnotation.as_view(),
-        name="upload-measurement_annotation",
-    ),
-    path(
-        "upload_boolean_classification_annotation/",
-        views.UploadBooleanClassificationAnnotation.as_view(),
-        name="upload-boolean-classification-annotation",
-    ),
-    path(
-        "upload_polygon_annotation/",
-        views.UploadPolygonAnnotationSet.as_view(),
-        name="upload-polygon-annotation",
-    ),
-    path(
-        "set_element_spacing_for_image/",
-        views.SetElementSpacingForImage.as_view(),
-        name="set-element-spacing-for-image",
-    ),
 ]
diff --git a/app/grandchallenge/retina_importers/views.py b/app/grandchallenge/retina_importers/views.py
--- a/app/grandchallenge/retina_importers/views.py
+++ b/app/grandchallenge/retina_importers/views.py
@@ -1,40 +1,14 @@
-from pathlib import Path
-from tempfile import TemporaryDirectory
-
-import SimpleITK as sitk
-from django.core.exceptions import (
-    ObjectDoesNotExist,
-    ValidationError,
-    MultipleObjectsReturned,
-)
-from rest_framework import generics, parsers, status, serializers
+from django.core.exceptions import ObjectDoesNotExist, ValidationError
+from rest_framework import generics, parsers, status
 import datetime
 import sys
 from io import BytesIO
 from django.http.response import JsonResponse
 from django.core.files.uploadedfile import InMemoryUploadedFile
-from django.db import IntegrityError, transaction
 from django.core.files import File
 from django.conf import settings
-from django.contrib.auth import get_user_model
-from django.contrib.auth.models import Group
+
 from .utils import upperize, exclude_val_from_dict
-from grandchallenge.annotations.models import (
-    ETDRSGridAnnotation,
-    BooleanClassificationAnnotation,
-    MeasurementAnnotation,
-    PolygonAnnotationSet,
-    SinglePolygonAnnotation,
-    LandmarkAnnotationSet,
-    SingleLandmarkAnnotation,
-)
-from grandchallenge.annotations.serializers import (
-    ETDRSGridAnnotationSerializer,
-    BooleanClassificationAnnotationSerializer,
-    MeasurementAnnotationSerializer,
-    PolygonAnnotationSetSerializer,
-    SingleLandmarkAnnotationSerializer,
-)
 from grandchallenge.archives.models import Archive
 from grandchallenge.archives.serializers import ArchiveSerializer
 from grandchallenge.patients.models import Patient
@@ -45,13 +19,6 @@
 from grandchallenge.cases.models import Image, ImageFile
 from grandchallenge.cases.serializers import ImageSerializer
 from grandchallenge.challenges.models import ImagingModality
-from .serializers import (
-    UploadETDRSGridAnnotationSerializer,
-    UploadBooleanClassificationAnnotationSerializer,
-    UploadMeasurementAnnotationSerializer,
-    UploadPolygonAnnotationSetSerializer,
-    UploadLandmarkAnnotationSetSerializer,
-)
 from .mixins import RetinaImportPermission
 
 
@@ -292,391 +259,3 @@ def save_mhd_and_raw_files(self, request, img):
             extension = "zraw" if image_key == "image_raw" else "mhd"
             image_name = f"{file_name}.{extension}"
             img_file_model.file.save(image_name, image_file, save=True)
-
-
-class AbstractUploadView(generics.CreateAPIView):
-    permission_classes = (RetinaImportPermission,)
-    parser_classes = (parsers.JSONParser,)
-    response = {}
-
-    # keys that should be removed from request.data.get("data") when saving
-    delete_keys = ("study_identifier", "series_identifier", "image_identifier")
-
-    # define these variables in upload views that implement this abstract class
-    queryset = None
-    serializer_class = None  # Upload data serializer
-    child_serializer_class = None  # Child model serializer
-    parent_model_class = None  # parent model
-    child_model_class = (
-        None
-    )  # child model (for models in request.data.get("data")
-
-    def handle_validation(self, serializer, request):
-        serializer = serializer(data=request.data)
-        valid = serializer.is_valid()
-        if not valid:
-            self.response.update({"errors": serializer.errors})
-            return None, None, None, None, None
-
-        try:
-            archive = Archive.objects.get(
-                name=request.data.get("archive_identifier")
-            )
-        except Archive.DoesNotExist:
-            r = "Archive does not exist: {}".format(
-                request.data.get("archive_identifier")
-            )
-            self.response.update({"errors": [r]})
-            return None, None, None, None, None
-
-        if request.data.get("patient_identifier") != "None":
-            patient = Patient.objects.get(
-                name=request.data.get("patient_identifier")
-            )
-        else:
-            patient = None
-
-        grader_group, group_created = Group.objects.get_or_create(
-            name=settings.RETINA_GRADERS_GROUP_NAME
-        )
-
-        grader, user_created = get_user_model().objects.get_or_create(
-            username=request.data.get("user_identifier").lower()
-        )
-
-        if (
-            user_created
-            or not grader.groups.filter(
-                name=settings.RETINA_GRADERS_GROUP_NAME
-            ).exists()
-        ):
-            grader_group.user_set.add(grader)
-
-        annotation_datetime = datetime.datetime.strptime(
-            request.data.get("datetime"), "%Y-%m-%dT%H:%M:%S.%f%z"
-        )
-
-        return archive, patient, grader, user_created, annotation_datetime
-
-    def trace_image_through_parents(self, data, patient):
-        try:
-            study = Study.objects.get(
-                name=data["study_identifier"], patient=patient
-            )
-            if data["image_identifier"] == "obs_000":
-                image = Image.objects.get(
-                    name=data["series_identifier"],
-                    modality__modality=settings.MODALITY_CF,
-                    study=study,
-                )
-            elif data["image_identifier"] == "oct":
-                image = Image.objects.get(
-                    name=data["series_identifier"],
-                    modality=ImagingModality.objects.get(
-                        modality=settings.MODALITY_OCT
-                    ),
-                    study=study,
-                )
-            else:
-                image = Image.objects.get(
-                    name=data["image_identifier"], study=study
-                )
-        except ObjectDoesNotExist:
-            error = f"Non-existant object. Data: {data}"
-            self.response.update({"errors": error})
-            return None
-
-        return image
-
-    def trace_image_through_archive(
-        self, image_identifier, archive_identifier
-    ):
-        try:
-            image = Image.objects.get(
-                name=image_identifier, archive__name=archive_identifier
-            )
-            return image
-        except ObjectDoesNotExist:
-            error = f"Non-existant object. Image: {image_identifier}, Archive: {archive_identifier}"
-            self.response.update({"errors": error})
-            return None
-        except MultipleObjectsReturned:
-            error = f"Multiple objects returned. Image: {image_identifier}, Archive: {archive_identifier}"
-            self.response.update({"errors": error})
-            return None
-
-    def create_or_return_duplicate_error_message(self, model, unique_args):
-        try:
-            with transaction.atomic():
-                model.save()
-            return model
-        except (IntegrityError, serializers.ValidationError):
-            args_arr = []
-            for key, item in unique_args.items():
-                args_arr.append(f"{key}: {item}")
-
-            class_name = model.__class__.__name__
-
-            msg = "{} already exists for {}".format(
-                class_name, ", ".join(args_arr)
-            )
-            self.response.update({"errors": {"duplicate": msg}})
-
-            return model
-
-    def post(self, request, *args, **kwargs):
-        self.response = {"success": False}
-
-        archive, patient, grader, user_created, annotation_datetime = self.handle_validation(
-            self.serializer_class, request
-        )
-        if "errors" in self.response:
-            return JsonResponse(
-                self.response, status=status.HTTP_400_BAD_REQUEST
-            )
-
-        if self.parent_model_class == LandmarkAnnotationSet:
-            parent_model = self.parent_model_class(
-                grader=grader, created=annotation_datetime
-            )
-
-            saved_model = self.create_or_return_duplicate_error_message(
-                parent_model,
-                {
-                    "grader": grader.username,
-                    "created": annotation_datetime.strftime(
-                        "%Y-%m-%dT%H:%M:%S.%f%z"
-                    ),
-                },
-            )
-            if "errors" in self.response:
-                return JsonResponse(
-                    self.response, status=status.HTTP_400_BAD_REQUEST
-                )
-
-        if self.child_model_class:
-            child_bulk_save_models = []
-            serialized_models = []
-            for annotation in request.data.get("data"):
-                if archive.name == "kappadata":
-                    image = self.trace_image_through_archive(
-                        annotation["image_identifier"], archive.name
-                    )
-                else:
-                    image = self.trace_image_through_parents(
-                        annotation, patient
-                    )
-                if "errors" in self.response:
-                    return JsonResponse(
-                        self.response,
-                        status=status.HTTP_500_INTERNAL_SERVER_ERROR,
-                    )
-
-                for k in self.delete_keys:
-                    annotation.pop(k, None)
-
-                if self.parent_model_class == LandmarkAnnotationSet:
-                    # ImageRegistration2D specific code
-                    annotation["annotation_set"] = saved_model
-                    single_child_model = self.child_model_class(
-                        image=image, **annotation
-                    )
-                    child_bulk_save_models.append(single_child_model)
-                    serialized_models.append(
-                        self.child_serializer_class(single_child_model).data
-                    )
-                else:
-                    polygon_value = None
-                    if self.child_model_class == PolygonAnnotationSet:
-                        # PolygonAnnotationSet specific code
-                        polygon_value = annotation.pop("value")
-
-                    child_model = self.child_model_class(
-                        grader=grader,
-                        created=annotation_datetime,
-                        image=image,
-                        **annotation,
-                    )
-
-                    saved_model = self.create_or_return_duplicate_error_message(
-                        child_model,
-                        {
-                            "grader": grader.username,
-                            "image": image,
-                            "created": annotation_datetime.strftime(
-                                "%Y-%m-%dT%H:%M:%S.%f%z"
-                            ),
-                        },
-                    )
-
-                    if "errors" in self.response:
-                        return JsonResponse(
-                            self.response, status=status.HTTP_400_BAD_REQUEST
-                        )
-                    else:
-                        serialized_models.append(
-                            self.child_serializer_class(saved_model).data
-                        )
-
-                    if self.child_model_class == PolygonAnnotationSet:
-                        # PolygonAnnotationSet specific code
-                        # Create single polygon annotations and bind to set
-                        for polygon in polygon_value:
-                            if len(polygon) > 0:
-                                child_bulk_save_models.append(
-                                    SinglePolygonAnnotation(
-                                        value=polygon,
-                                        annotation_set=saved_model,
-                                    )
-                                )
-                        if len(child_bulk_save_models) > 0:
-                            SinglePolygonAnnotation.objects.bulk_create(
-                                child_bulk_save_models
-                            )
-                            child_bulk_save_models = []
-
-            if len(child_bulk_save_models) > 0:
-                self.child_model_class.objects.bulk_create(
-                    child_bulk_save_models
-                )
-            self.response.update(
-                {
-                    "success": True,
-                    "user_created": user_created,
-                    "grader": grader.username,
-                    "model": serialized_models,
-                }
-            )
-
-            return JsonResponse(self.response, status=status.HTTP_201_CREATED)
-
-
-class UploadLandmarkAnnotationSet(AbstractUploadView):
-    queryset = LandmarkAnnotationSet.objects.all()
-    serializer_class = (
-        UploadLandmarkAnnotationSetSerializer
-    )  # Upload data serializer
-    child_serializer_class = (
-        SingleLandmarkAnnotationSerializer
-    )  # Child model serializer
-    parent_model_class = LandmarkAnnotationSet  # parent model
-    child_model_class = (
-        SingleLandmarkAnnotation
-    )  # child model (for models in request.data.get("data")
-
-
-class UploadETDRSGridAnnotation(AbstractUploadView):
-    queryset = ETDRSGridAnnotation.objects.all()
-    serializer_class = (
-        UploadETDRSGridAnnotationSerializer
-    )  # Upload data serializer
-    child_serializer_class = (
-        ETDRSGridAnnotationSerializer
-    )  # Child model serializer
-    parent_model_class = None  # parent model
-    child_model_class = (
-        ETDRSGridAnnotation
-    )  # child model (for models in request.data.get("data")
-
-
-class UploadMeasurementAnnotation(AbstractUploadView):
-    queryset = MeasurementAnnotation.objects.all()
-    serializer_class = (
-        UploadMeasurementAnnotationSerializer
-    )  # Upload data serializer
-    child_serializer_class = (
-        MeasurementAnnotationSerializer
-    )  # Child model serializer
-    parent_model_class = None  # parent model
-    child_model_class = (
-        MeasurementAnnotation
-    )  # child model (for models in request.data.get("data")
-
-
-class UploadBooleanClassificationAnnotation(AbstractUploadView):
-    queryset = BooleanClassificationAnnotation.objects.all()
-    serializer_class = (
-        UploadBooleanClassificationAnnotationSerializer
-    )  # Upload data serializer
-    child_serializer_class = (
-        BooleanClassificationAnnotationSerializer
-    )  # Child model serializer
-    parent_model_class = None  # parent model
-    child_model_class = (
-        BooleanClassificationAnnotation
-    )  # child model (for models in request.data.get("data")
-
-
-class UploadPolygonAnnotationSet(AbstractUploadView):
-    queryset = PolygonAnnotationSet.objects.all()
-    serializer_class = UploadPolygonAnnotationSetSerializer
-    child_serializer_class = PolygonAnnotationSetSerializer
-    parent_model_class = None
-    child_model_class = PolygonAnnotationSet
-
-
-class SetElementSpacingForImage(generics.GenericAPIView):
-    queryset = Image.objects.all()
-    permission_classes = (RetinaImportPermission,)
-    parser_classes = (parsers.JSONParser,)
-
-    def post(self, request, *args, **kwargs):
-        response = self.set_element_spacing(request)
-        response_status = status.HTTP_200_OK
-        if "errors" in response:
-            response_status = status.HTTP_400_BAD_REQUEST
-        return JsonResponse(response, status=response_status)
-
-    def set_element_spacing(self, request):
-        is_3d = False
-        image_name = request.data.get("image_identifier")
-        study_name = request.data.get("study_identifier")
-        sub_image_name = request.data.get("sub_image_name")
-        values = {"name": image_name}
-        if study_name is not None:
-            values.update({"study__name": study_name})
-        if sub_image_name is not None and sub_image_name.lower() == "oct":
-            values.update(
-                {
-                    "modality": ImagingModality.objects.get(
-                        modality=settings.MODALITY_OCT
-                    )
-                }
-            )
-            is_3d = True
-        try:
-            image = Image.objects.get(**values)
-        except MultipleObjectsReturned:
-            return {"errors": "Image identifiers returns multiple images."}
-        except ObjectDoesNotExist:
-            return {"errors": "Image does not exist"}
-
-        es_x = request.data.get("element_spacing_x", 1)
-        es_y = request.data.get("element_spacing_y", 1)
-        es_z = request.data.get("element_spacing_z", 1)
-        spacing = (es_x, es_y, es_z) if is_3d else (es_x, es_y)
-
-        try:
-            self.set_mhd_element_spacing_header(image, spacing)
-            return {"success": True}
-        except Exception as e:
-            return {"errors": str(e)}
-
-    @staticmethod
-    def set_mhd_element_spacing_header(image, spacing):
-        sitk_image = image.get_sitk_image()
-        old_mhd = image.files.get(file__endswith=".mhd")
-        old_raw = image.files.get(file__endswith="raw")
-
-        sitk_image.SetSpacing(spacing)
-        with TemporaryDirectory() as tempdirname:
-            sitk.WriteImage(
-                sitk_image, str(Path(tempdirname) / Path("out.mhd")), True
-            )
-            for file in (("out.mhd", old_mhd), ("out.zraw", old_raw)):
-                bio = BytesIO()
-                with open(str(Path(tempdirname) / Path(file[0])), "rb") as fh:
-                    bio.name = fh.name
-                    bio.write(fh.read())
-                bio.seek(0)
-                file[1].file.save(file[0], bio, save=True)


Test patch:
diff --git a/app/tests/retina_api_tests/test_views.py b/app/tests/retina_api_tests/test_views.py
--- a/app/tests/retina_api_tests/test_views.py
+++ b/app/tests/retina_api_tests/test_views.py
@@ -356,22 +356,3 @@ def test_returns_correct_spacing(self, client):
         assert response.status_code == status.HTTP_200_OK
         r = response.json()
         assert list(image.get_sitk_image().GetSpacing()) == r
-
-    def test_returns_correct_spacing_changed(self, client):
-        image = ImageFactoryWithImageFile()
-        image.permit_viewing_by_retina_users()
-        element_spacing = (1.5, 0.5)
-        response = create_element_spacing_request(
-            client, image_name=image.name, es=element_spacing
-        )
-        assert response.status_code == status.HTTP_200_OK
-        r = response.json()
-        assert r["success"]
-        assert element_spacing == image.get_sitk_image().GetSpacing()
-
-        url = reverse("retina:api:image-element-spacing-view", args=[image.pk])
-        client, _ = client_login(client, user="retina_user")
-        response = client.get(url)
-        assert response.status_code == status.HTTP_200_OK
-        r = response.json()
-        assert list(image.get_sitk_image().GetSpacing()) == r
diff --git a/app/tests/retina_importers_tests/test_data/upload_boolean_invalid_data.json b/app/tests/retina_importers_tests/test_data/upload_boolean_invalid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_boolean_invalid_data.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "archive_identifier": "Australia",
-  "patient_identifier": "0008",
-  "user_identifier": "Ada",
-  "datetime": "2018-01-19T09:11:50.256326+0100",
-  "data": [
-    {
-      "series_identifier": "BMES10008L-M.jpg",
-      "image_identifier": "BMES10008L-M.jpg",
-      "name": "fovea_affected",
-      "value": true,
-      "study_identifier": "BMES1"
-    },
-    {
-      "series_identifier": "BMES20008L-M.jpg",
-      "image_identifier": "BMES20008L-M.jpg",
-      "name": "fovea_affected",
-      "value": "",
-      "study_identifier": "BMES2"
-    }
-  ]
-}
-
diff --git a/app/tests/retina_importers_tests/test_data/upload_boolean_valid_data.json b/app/tests/retina_importers_tests/test_data/upload_boolean_valid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_boolean_valid_data.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "archive_identifier": "Australia",
-  "patient_identifier": "0008",
-  "user_identifier": "Ada",
-  "datetime": "2018-01-19T09:11:50.256326+0100",
-  "data": [
-    {
-      "series_identifier": "BMES10008L-M.jpg",
-      "image_identifier": "BMES10008L-M.jpg",
-      "name": "fovea_affected",
-      "value": true,
-      "study_identifier": "BMES1"
-    },
-    {
-      "series_identifier": "BMES20008L-M.jpg",
-      "image_identifier": "BMES20008L-M.jpg",
-      "name": "fovea_affected",
-      "value": false,
-      "study_identifier": "BMES2"
-    }
-  ]
-}
-
diff --git a/app/tests/retina_importers_tests/test_data/upload_etdrs_invalid_data.json b/app/tests/retina_importers_tests/test_data/upload_etdrs_invalid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_etdrs_invalid_data.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "archive_identifier": "Australia",
-  "patient_identifier": "0008",
-  "user_identifier": "Ada",
-  "datetime": "2018-01-19T09:11:50.256326+0100",
-  "data": [
-    {
-      "series_identifier": "BMES10008L-M.jpg",
-      "image_identifier": "BMES10008L-M.jpg",
-      "fovea": [
-        2271.2079207920788,
-        1435.5445544554455
-      ],
-      "optic_disk": [
-        1241.4653465346535
-      ],
-      "study_identifier": "BMES1"
-    },
-    {
-      "series_identifier": "BMES20008L-M.jpg",
-      "image_identifier": "BMES20008L-M.jpg",
-      "fovea": [
-        2045.5721021553145,
-        1361.6084793652637
-      ],
-      "optic_disk": [
-        992.1652592345704,
-        1125.025429232876
-      ],
-      "study_identifier": "BMES2"
-    }
-  ]
-}
-
diff --git a/app/tests/retina_importers_tests/test_data/upload_etdrs_valid_data.json b/app/tests/retina_importers_tests/test_data/upload_etdrs_valid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_etdrs_valid_data.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "archive_identifier": "Australia",
-  "patient_identifier": "0008",
-  "user_identifier": "Ada",
-  "datetime": "2018-01-19T09:11:50.256326+0100",
-  "data": [
-    {
-      "series_identifier": "BMES10008L-M.jpg",
-      "image_identifier": "BMES10008L-M.jpg",
-      "fovea": [
-        2271.2079207920788,
-        1435.5445544554455
-      ],
-      "optic_disk": [
-        1241.4653465346535,
-        1166.079207920792
-      ],
-      "study_identifier": "BMES1"
-    },
-    {
-      "series_identifier": "BMES20008L-M.jpg",
-      "image_identifier": "BMES20008L-M.jpg",
-      "fovea": [
-        2045.5721021553145,
-        1361.6084793652637
-      ],
-      "optic_disk": [
-        992.1652592345704,
-        1125.025429232876
-      ],
-      "study_identifier": "BMES2"
-    }
-  ]
-}
-
diff --git a/app/tests/retina_importers_tests/test_data/upload_measurement_invalid_data.json b/app/tests/retina_importers_tests/test_data/upload_measurement_invalid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_measurement_invalid_data.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "start_voxel": [2271.2079207920788, 1435.5445544554455],
-            "end_voxel": [2271.2079207920788, 1435.5445544554455],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "start_voxel": [2271.2079207920788, 1435.5445544554455],
-            "end_voxel": [2271.2079207920788, 1435.5445544554455],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "start_voxel": [2271.2079207920788, 1435.5445544554455],
-            "end_voxel": [],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_data/upload_measurement_valid_data.json b/app/tests/retina_importers_tests/test_data/upload_measurement_valid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_measurement_valid_data.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "start_voxel": [2271.2079207920788, 1435.5445544554455],
-            "end_voxel": [2271.2079207920788, 1435.5445544554455],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "start_voxel": [2271.2079207920788, 1435.5445544554455],
-            "end_voxel": [2271.2079207920788, 1435.5445544554455],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_data/upload_polygon_invalid_data.json b/app/tests/retina_importers_tests/test_data/upload_polygon_invalid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_polygon_invalid_data.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "name": "macular",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "name": "peripapillar",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "name": "peripapillar",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_data/upload_polygon_valid_data.json b/app/tests/retina_importers_tests/test_data/upload_polygon_valid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_polygon_valid_data.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "name": "macular",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "name": "peripapillar",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "name": "peripapillar",
-            "value": [
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ],
-                [
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455],
-                    [2271.2079207920788, 1435.5445544554455]
-                ]
-            ],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_data/upload_registration_invalid_data.json b/app/tests/retina_importers_tests/test_data/upload_registration_invalid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_registration_invalid_data.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "landmarks": [
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "landmarks": [
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "landmarks": [
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455]
-            ],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_data/upload_registration_valid_data.json b/app/tests/retina_importers_tests/test_data/upload_registration_valid_data.json
deleted file mode 100644
--- a/app/tests/retina_importers_tests/test_data/upload_registration_valid_data.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-    "archive_identifier": "Australia",
-    "patient_identifier": "0008",
-    "user_identifier": "Ada",
-    "datetime": "2018-01-19T09:11:50.256326+0100",
-    "data": [
-        {
-            "series_identifier": "BMES10008L-M.jpg",
-            "image_identifier": "BMES10008L-M.jpg",
-            "landmarks": [
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455]
-            ],
-            "study_identifier": "BMES1"
-        },
-        {
-            "series_identifier": "BMES20008L-M.jpg",
-            "image_identifier": "BMES20008L-M.jpg",
-            "landmarks": [
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455],
-                [2271.2079207920788, 1435.5445544554455]
-            ],
-            "study_identifier": "BMES2"
-        }
-    ]
-}
diff --git a/app/tests/retina_importers_tests/test_views.py b/app/tests/retina_importers_tests/test_views.py
--- a/app/tests/retina_importers_tests/test_views.py
+++ b/app/tests/retina_importers_tests/test_views.py
@@ -40,27 +40,6 @@
         ("upload_image_rsbmes", "retina:importers:upload-image", False),
         ("upload_image_kappa", "retina:importers:upload-image", False),
         ("upload_image_areds", "retina:importers:upload-image", False),
-        (
-            "upload_etdrs",
-            "retina:importers:upload-etdrs-grid-annotation",
-            True,
-        ),
-        (
-            "upload_measurement",
-            "retina:importers:upload-measurement_annotation",
-            True,
-        ),
-        (
-            "upload_boolean",
-            "retina:importers:upload-boolean-classification-annotation",
-            True,
-        ),
-        ("upload_polygon", "retina:importers:upload-polygon-annotation", True),
-        (
-            "upload_registration",
-            "retina:importers:upload-image-registration-landmarks",
-            True,
-        ),
     ],
 )
 class TestCustomUploadEndpoints:
@@ -147,108 +126,3 @@ def test_existing_image(self, client, user, expected_status, access):
         if access:
             response = r.json()
             assert response["exists"]
-
-
-@pytest.mark.django_db
-@pytest.mark.parametrize(
-    "user,expected_status, access",
-    [
-        ("anonymous", status.HTTP_401_UNAUTHORIZED, False),
-        ("normal", status.HTTP_403_FORBIDDEN, False),
-        ("staff", status.HTTP_403_FORBIDDEN, False),
-        ("import_user", status.HTTP_200_OK, True),
-    ],
-)
-class TestSetElementSpacingEndpointAuthentication:
-    def test_authentication(self, client, user, expected_status, access):
-        response = create_element_spacing_request(client, user=user)
-        assert response.status_code == expected_status
-        if access:
-            data = response.json()
-            assert data["success"]
-
-
-@pytest.mark.django_db
-class TestSetElementSpacingEndpointErrors:
-    def test_non_existing_image_error(self, client):
-        image = ImageFactoryWithImageFile()
-        image_name = image.name
-        image.delete()
-        response = create_element_spacing_request(
-            client, image_name=image_name
-        )
-
-        assert response.status_code == status.HTTP_400_BAD_REQUEST
-        r = response.json()
-        assert "errors" in r
-        assert r["errors"] == "Image does not exist"
-
-    def test_non_existing_imagefile_error(self, client):
-        image = ImageFactory()
-        response = create_element_spacing_request(
-            client, image_name=image.name
-        )
-
-        assert response.status_code == status.HTTP_400_BAD_REQUEST
-        r = response.json()
-        assert "errors" in r
-        assert r["errors"] == "ImageFile matching query does not exist."
-
-    def test_multiple_images_error(self, client):
-        image = ImageFactoryWithImageFile()
-        ImageFactoryWithImageFile(name=image.name)
-        response = create_element_spacing_request(
-            client, image_name=image.name
-        )
-
-        assert response.status_code == status.HTTP_400_BAD_REQUEST
-        r = response.json()
-        assert "errors" in r
-        assert r["errors"] == "Image identifiers returns multiple images."
-
-
-@pytest.mark.django_db
-class TestSetElementSpacingEndpoint:
-    def test_spacing_changes(self, client):
-        image = ImageFactoryWithImageFile()
-        element_spacing = (1.5, 0.5)
-        sitk_image = image.get_sitk_image()
-        original_spacing = sitk_image.GetSpacing()
-        assert element_spacing != original_spacing
-
-        response = create_element_spacing_request(
-            client, image_name=image.name, es=element_spacing
-        )
-
-        assert response.status_code == status.HTTP_200_OK
-        r = response.json()
-        assert r["success"]
-
-        assert element_spacing == image.get_sitk_image().GetSpacing()
-
-    def test_image_with_study(self, client):
-        image = ImageFactoryWithImageFile()
-        ImageFactoryWithImageFile(name=image.name)
-        response = create_element_spacing_request(
-            client, image_name=image.name, study=image.study
-        )
-        assert response.status_code == status.HTTP_200_OK
-        r = response.json()
-        assert r["success"]
-
-    def test_spacing_changes_3d(self, client):
-        image = ImageFactoryWithImageFile3D()
-        element_spacing = (2.5, 1.5, 0.5)
-        sitk_image = image.get_sitk_image()
-        original_spacing = sitk_image.GetSpacing()
-        assert element_spacing != original_spacing
-
-        response = create_element_spacing_request(
-            client, image_name=image.name, es=element_spacing, is_3d=True
-        )
-
-        assert response.status_code == status.HTTP_200_OK
-        r = response.json()
-        assert r["success"]
-
-        assert element_spacing == image.get_sitk_image().GetSpacing()