Skip to content

Commit

Permalink
update ZoneCreateAPIView return data status codes (#2036)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Nov 18, 2024
1 parent dc19d61 commit a10a2e8
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Changed
- Update REST API versioning (#1936)
- Update REST API views for OpenAPI compatibility (#1951)
- Return ``503`` in ``ZoneSubmitMoveAPIView`` if project is locked (#1847)
- Return ``503`` in ``ZoneCreateAPIView`` if no investigation or iRODS collections (#2036)
- **Samplesheets**
- Update REST API versioning (#1936)
- Update REST API views for OpenAPI compatibility (#1951)
Expand Down
6 changes: 6 additions & 0 deletions docs_manual/source/sodar_release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Release for SODAR Core v1.0 upgrade, iRODS v4.3 upgrade and feature updates.
- Update REST API versioning
- Update REST API views for OpenAPI support
- Update lock requiring REST API views to return 503 if project is locked
- Update landing zone creation REST API view to return 503 if no investigation
or iRODS collections
- Upgrade to Postgres v16
- Upgrade to python-irodsclient v2.2.0
- Upgrade to SODAR Core v1.0.2
Expand Down Expand Up @@ -73,6 +75,10 @@ REST API Updates
* ``IrodsDataRequestAcceptAPIView``
+ Return ``503`` if project is locked
- Landing Zones API
* ``ZoneCreateAPIView``
+ Return ``503`` if Taskflow is not enabled
+ Return ``503`` if investigation for project is not found
+ Return ``503`` if project iRODS collections have not been created
* ``ZoneSubmitMoveAPIView``
+ Return ``503`` if project is locked

Expand Down
16 changes: 15 additions & 1 deletion landingzones/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""API view model serializers for the landingzone app"""

from rest_framework import serializers
from rest_framework.exceptions import APIException

# Projectroles dependency
from projectroles.plugins import get_backend_api
Expand All @@ -10,7 +11,7 @@
)

# Samplesheets dependency
from samplesheets.models import Assay
from samplesheets.models import Investigation, Assay

from landingzones.constants import (
ZONE_STATUS_OK,
Expand All @@ -21,6 +22,10 @@
from landingzones.utils import get_zone_title


# Local constants
ZONE_NO_INV_MSG = 'No investigation found for project'


class LandingZoneSerializer(SODARProjectModelSerializer):
"""Serializer for the LandingZone model"""

Expand Down Expand Up @@ -68,6 +73,15 @@ def get_irods_path(self, obj):
return irods_backend.get_path(obj)

def validate(self, attrs):
# If there is no investigation, we can't have a landing zone
investigation = Investigation.objects.filter(
project=self.context.get('project'), active=True
).first()
if not investigation:
ex = APIException(ZONE_NO_INV_MSG)
ex.status_code = 503
raise ex
# Else continue validating the input
try:
if 'assay' in attrs:
assay = Assay.objects.get(
Expand Down
8 changes: 6 additions & 2 deletions landingzones/tests/test_views_api_taskflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
ZONE_STATUS_FAILED,
)
from landingzones.models import LandingZone
from landingzones.serializers import ZONE_NO_INV_MSG
from landingzones.tests.test_models import LandingZoneMixin
from landingzones.tests.test_views_taskflow import (
LandingZoneTaskflowMixin,
Expand All @@ -44,6 +45,7 @@
from landingzones.views_api import (
LANDINGZONES_API_MEDIA_TYPE,
LANDINGZONES_API_DEFAULT_VERSION,
ZONE_NO_COLLS_MSG,
)


Expand Down Expand Up @@ -290,7 +292,8 @@ def test_post_no_investigation(self):
'config_data': {},
}
response = self.request_knox(self.url, method='POST', data=request_data)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.status_code, 503)
self.assertEqual(ZONE_NO_INV_MSG, response.data['detail'])
self.assertEqual(LandingZone.objects.count(), 0)

def test_post_no_irods_collections(self):
Expand All @@ -306,7 +309,8 @@ def test_post_no_irods_collections(self):
'config_data': {},
}
response = self.request_knox(self.url, method='POST', data=request_data)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.status_code, 503)
self.assertIn(ZONE_NO_COLLS_MSG, response.data['detail'])
self.assertEqual(LandingZone.objects.count(), 0)


Expand Down
29 changes: 17 additions & 12 deletions landingzones/views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from django.urls import reverse

from rest_framework import status
from rest_framework.exceptions import APIException, NotFound
from rest_framework.generics import (
ListAPIView,
Expand All @@ -14,7 +15,6 @@
)
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.serializers import ValidationError
from rest_framework.schemas.openapi import AutoSchema
from rest_framework.versioning import AcceptHeaderVersioning
Expand Down Expand Up @@ -51,6 +51,8 @@
LANDINGZONES_API_ALLOWED_VERSIONS = ['1.0']
LANDINGZONES_API_DEFAULT_VERSION = '1.0'

ZONE_NO_COLLS_MSG = 'iRODS collections not created for project'


# Mixins and Base Views --------------------------------------------------------

Expand Down Expand Up @@ -214,6 +216,9 @@ class ZoneCreateAPIView(
"""
Create a landing zone.
Returns ``503`` if an investigation for the project is not found or project
iRODS collections have not been created.
**URL:** ``/landingzones/api/create/{Project.sodar_uuid}``
**Methods:** ``POST``
Expand All @@ -237,29 +242,29 @@ class ZoneCreateAPIView(
permission_required = 'landingzones.create_zone'
serializer_class = LandingZoneSerializer

@classmethod
def _raise_503(cls, msg):
ex = APIException(msg)
ex.status_code = 503
raise ex

def perform_create(self, serializer):
"""
Override perform_create() to add timeline event and initiate taskflow.
"""
ex_msg = 'Creating landing zone failed: '
ex_prefix = 'Creating landing zone failed: '
# Check taskflow status
if not get_backend_api('taskflow'):
raise APIException('{}Taskflow not enabled'.format(ex_msg))
self._raise_503('{}Taskflow not enabled'.format(ex_prefix))

# Ensure project has investigation with iRODS collections created
project = self.get_project()
investigation = Investigation.objects.filter(
active=True, project=project
).first()

if not investigation:
raise ValidationError(
'{}No investigation found for project'.format(ex_msg)
)
# NOTE: Lack of investigation is already caught in serializer
if not investigation.irods_status:
raise ValidationError(
'{}iRODS collections not created for project'.format(ex_msg)
)
self._raise_503('{}{}'.format(ex_prefix, ZONE_NO_COLLS_MSG))

# If all is OK, go forward with object creation and taskflow submission
create_colls = serializer.validated_data.pop('create_colls')
Expand All @@ -273,7 +278,7 @@ def perform_create(self, serializer):
request=self.request,
)
except Exception as ex:
raise APIException('{}{}'.format(ex_msg, ex))
raise APIException('{}{}'.format(ex_prefix, ex))


class ZoneUpdateAPIView(
Expand Down

0 comments on commit a10a2e8

Please sign in to comment.