From 7aec60b066bbadfc520e073adb3fe26be9ae7ead Mon Sep 17 00:00:00 2001 From: Daniel Chiquito Date: Mon, 10 Jan 2022 13:10:45 -0500 Subject: [PATCH 1/4] Add asset info endpoint to AssetViewSet --- dandiapi/api/tests/test_asset.py | 19 +++++++++++++++++++ dandiapi/api/views/asset.py | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/dandiapi/api/tests/test_asset.py b/dandiapi/api/tests/test_asset.py index 62af38cb9..7bb909b68 100644 --- a/dandiapi/api/tests/test_asset.py +++ b/dandiapi/api/tests/test_asset.py @@ -343,6 +343,25 @@ def test_asset_rest_retrieve_no_sha256(api_client, version, asset): ) +@pytest.mark.django_db +def test_asset_rest_info(api_client, version, asset): + version.assets.add(asset) + + assert api_client.get( + f'/api/dandisets/{version.dandiset.identifier}/' + f'versions/{version.version}/assets/{asset.asset_id}/info/' + ).json() == { + 'asset_id': str(asset.asset_id), + 'blob': str(asset.blob.blob_id), + 'zarr': None, + 'path': asset.path, + 'size': asset.size, + 'metadata': asset.metadata, + 'created': TIMESTAMP_RE, + 'modified': TIMESTAMP_RE, + } + + @pytest.mark.django_db @pytest.mark.parametrize( 'status,validation_error', diff --git a/dandiapi/api/views/asset.py b/dandiapi/api/views/asset.py index f89d5a3a9..ff35e8648 100644 --- a/dandiapi/api/views/asset.py +++ b/dandiapi/api/views/asset.py @@ -194,6 +194,17 @@ def retrieve(self, request, **kwargs): asset = self.get_object() return Response(asset.metadata, status=status.HTTP_200_OK) + @swagger_auto_schema( + manual_parameters=[ASSET_ID_PARAM, VERSIONS_DANDISET_PK_PARAM, VERSIONS_VERSION_PARAM], + responses={200: AssetDetailSerializer()}, + ) + @action(detail=True, methods=['GET']) + def info(self, request, **kwargs): + """Django serialization of an asset.""" + asset = self.get_object() + serializer = AssetDetailSerializer(instance=asset) + return Response(serializer.data, status=status.HTTP_200_OK) + @swagger_auto_schema( responses={200: AssetValidationSerializer()}, manual_parameters=[ASSET_ID_PARAM, VERSIONS_DANDISET_PK_PARAM, VERSIONS_VERSION_PARAM], From 6032d2f8302e581572fdf33d6fed6ba5e635f8b6 Mon Sep 17 00:00:00 2001 From: Daniel Chiquito Date: Mon, 10 Jan 2022 13:11:38 -0500 Subject: [PATCH 2/4] Add general asset info endpoint --- dandiapi/api/tests/test_asset.py | 14 ++++++++++++++ dandiapi/api/views/__init__.py | 3 ++- dandiapi/api/views/asset.py | 12 ++++++++++++ dandiapi/urls.py | 6 ++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/dandiapi/api/tests/test_asset.py b/dandiapi/api/tests/test_asset.py index 7bb909b68..1466b7f56 100644 --- a/dandiapi/api/tests/test_asset.py +++ b/dandiapi/api/tests/test_asset.py @@ -934,6 +934,20 @@ def test_asset_direct_metadata(api_client, asset): assert json.loads(api_client.get(f'/api/assets/{asset.asset_id}/').content) == asset.metadata +@pytest.mark.django_db +def test_asset_direct_info(api_client, asset): + assert api_client.get(f'/api/assets/{asset.asset_id}/info/').json() == { + 'asset_id': str(asset.asset_id), + 'blob': str(asset.blob.blob_id), + 'zarr': None, + 'path': asset.path, + 'size': asset.size, + 'metadata': asset.metadata, + 'created': TIMESTAMP_RE, + 'modified': TIMESTAMP_RE, + } + + @pytest.mark.parametrize( ('embargo_status'), [ diff --git a/dandiapi/api/views/__init__.py b/dandiapi/api/views/__init__.py index 79ce5a5c9..13973846f 100644 --- a/dandiapi/api/views/__init__.py +++ b/dandiapi/api/views/__init__.py @@ -1,4 +1,4 @@ -from .asset import AssetViewSet, asset_download_view, asset_metadata_view +from .asset import AssetViewSet, asset_download_view, asset_info_view, asset_metadata_view from .auth import auth_token_view, authorize_view, user_questionnaire_form_view from .dandiset import DandisetViewSet from .info import info_view @@ -21,6 +21,7 @@ 'ZarrViewSet', 'authorize_view', 'asset_download_view', + 'asset_info_view', 'asset_metadata_view', 'auth_token_view', 'blob_read_view', diff --git a/dandiapi/api/views/asset.py b/dandiapi/api/views/asset.py index ff35e8648..88242c6dd 100644 --- a/dandiapi/api/views/asset.py +++ b/dandiapi/api/views/asset.py @@ -148,6 +148,18 @@ def asset_metadata_view(request, asset_id): return JsonResponse(asset.metadata) +@swagger_auto_schema( + method='GET', + operation_summary='Django serialization of an asset', + manual_parameters=[ASSET_ID_PARAM], +) +@api_view(['GET', 'HEAD']) +def asset_info_view(request, asset_id): + asset = get_object_or_404(Asset, asset_id=asset_id) + serializer = AssetDetailSerializer(instance=asset) + return Response(serializer.data, status=status.HTTP_200_OK) + + class AssetRequestSerializer(serializers.Serializer): metadata = serializers.JSONField() blob_id = serializers.UUIDField(required=False) diff --git a/dandiapi/urls.py b/dandiapi/urls.py index 4b0768e1e..e6e847bbc 100644 --- a/dandiapi/urls.py +++ b/dandiapi/urls.py @@ -13,6 +13,7 @@ VersionViewSet, ZarrViewSet, asset_download_view, + asset_info_view, asset_metadata_view, auth_token_view, authorize_view, @@ -87,6 +88,11 @@ def to_url(self, value): asset_download_view, name='asset-direct-download', ), + re_path( + r'api/assets/(?P[0-9a-f\-]{36})/info/', + asset_info_view, + name='asset-direct-info', + ), path('api/auth/token/', auth_token_view, name='auth-token'), path('api/stats/', stats_view), path('api/info/', info_view), From 985b526a9e3ad9642649912d81824ca801327b98 Mon Sep 17 00:00:00 2001 From: Daniel Chiquito Date: Mon, 10 Jan 2022 13:11:51 -0500 Subject: [PATCH 3/4] Remove outdated TODO --- dandiapi/api/views/version.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dandiapi/api/views/version.py b/dandiapi/api/views/version.py index 66492bb41..d5a627e32 100644 --- a/dandiapi/api/views/version.py +++ b/dandiapi/api/views/version.py @@ -46,11 +46,6 @@ def retrieve(self, request, **kwargs): version = self.get_object() return Response(version.metadata, status=status.HTTP_200_OK) - # TODO clean up this action - # Originally retrieve() returned this, but the API specification was modified so that - # retrieve() only returns the metadata for a version, instead of a serialization. - # Unfortunately the web UI is built around VersionDetailSerializer, so this endpoint was - # added to avoid rewriting the web UI. @swagger_auto_schema( manual_parameters=[DANDISET_PK_PARAM, VERSION_PARAM], responses={200: VersionDetailSerializer()}, From 6c2be0b1057b8426d5ca861318b9235c94253e45 Mon Sep 17 00:00:00 2001 From: Daniel Chiquito Date: Mon, 10 Jan 2022 15:40:41 -0500 Subject: [PATCH 4/4] Add extra data to version and asset tests This has the effect of testing that the queryset filtering works to remove the extra versions/assets. --- dandiapi/api/tests/test_asset.py | 10 ++++++++-- dandiapi/api/tests/test_version.py | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dandiapi/api/tests/test_asset.py b/dandiapi/api/tests/test_asset.py index b0af29b26..b1bcbe72d 100644 --- a/dandiapi/api/tests/test_asset.py +++ b/dandiapi/api/tests/test_asset.py @@ -286,9 +286,12 @@ def test_asset_populate_metadata_zarr(draft_asset_factory, zarr_archive): @pytest.mark.django_db -def test_asset_rest_list(api_client, version, asset): +def test_asset_rest_list(api_client, version, asset, asset_factory): version.assets.add(asset) + # Create an extra asset so that there are multiple assets to filter down + asset_factory() + assert api_client.get( f'/api/dandisets/{version.dandiset.identifier}/versions/{version.version}/assets/' ).json() == { @@ -344,9 +347,12 @@ def test_asset_rest_list_ordering(api_client, version, asset_factory, order_para @pytest.mark.django_db -def test_asset_rest_retrieve(api_client, version, asset): +def test_asset_rest_retrieve(api_client, version, asset, asset_factory): version.assets.add(asset) + # Create an extra asset so that there are multiple assets to filter down + asset_factory() + assert ( api_client.get( f'/api/dandisets/{version.dandiset.identifier}/' diff --git a/dandiapi/api/tests/test_version.py b/dandiapi/api/tests/test_version.py index 012b5962c..f9d9e83b7 100644 --- a/dandiapi/api/tests/test_version.py +++ b/dandiapi/api/tests/test_version.py @@ -318,7 +318,10 @@ def test_version_publish_version(draft_version, asset): @pytest.mark.django_db -def test_version_rest_list(api_client, version): +def test_version_rest_list(api_client, version, draft_version_factory): + # Create an extra version so that there are multiple versions to filter down + draft_version_factory() + assert api_client.get(f'/api/dandisets/{version.dandiset.identifier}/versions/').data == { 'count': 1, 'next': None, @@ -345,7 +348,10 @@ def test_version_rest_list(api_client, version): @pytest.mark.django_db -def test_version_rest_retrieve(api_client, version): +def test_version_rest_retrieve(api_client, version, draft_version_factory): + # Create an extra version so that there are multiple versions to filter down + draft_version_factory() + assert ( api_client.get( f'/api/dandisets/{version.dandiset.identifier}/versions/{version.version}/'