From 1ba2bcf1a07d6f4c59020cc7fd5d9bf44a7ed47a Mon Sep 17 00:00:00 2001 From: Alexander J Sheehan Date: Thu, 8 Feb 2024 19:54:23 +0000 Subject: [PATCH] feat: new content metadata readonly viewset --- .../apps/api/v1/tests/test_views.py | 47 +++++++++++++++++++ enterprise_catalog/apps/api/v1/urls.py | 4 ++ .../apps/api/v1/views/content_metadata.py | 35 ++++++++++++++ .../apps/catalog/tests/factories.py | 26 ++++++++++ 4 files changed, 112 insertions(+) create mode 100644 enterprise_catalog/apps/api/v1/views/content_metadata.py diff --git a/enterprise_catalog/apps/api/v1/tests/test_views.py b/enterprise_catalog/apps/api/v1/tests/test_views.py index 8fc444dcd..d7847d68c 100644 --- a/enterprise_catalog/apps/api/v1/tests/test_views.py +++ b/enterprise_catalog/apps/api/v1/tests/test_views.py @@ -2366,3 +2366,50 @@ def test_list_with_missing_enterprise_customer(self): response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 0) + + +@ddt.ddt +class ContentMetadataViewTests(APITestMixin): + """ + Tests for the readonly ContentMetadata viewset. + """ + def setUp(self): + super().setUp() + self.set_up_staff() + self.content_metadata_object = ContentMetadataFactory( + content_type='course' + ) + + def test_list_success(self): + """ + Test a successful, expected api response for the metadata list endpoint + """ + url = reverse('api:v1:content-metadata-list') + response = self.client.get(url) + response_json = response.json() + assert len(response_json.get('results')) == 1 + assert response_json.get('results')[0].get("key") == self.content_metadata_object.content_key + + def test_list_with_content_keys(self): + """ + Test a successful, expected api response for the metadata list endpoint with a supplied content keys query + param + """ + url = reverse('api:v1:content-metadata-list') + f"?content_keys={self.content_metadata_object.content_key}" + response = self.client.get(url) + response_json = response.json() + assert len(response_json.get('results')) == 1 + assert response_json.get('results')[0].get("key") == self.content_metadata_object.content_key + assert response_json.get('results')[0].get("course_runs")[0].get('start') == '2024-02-12T11:00:00Z' + + def test_get_success(self): + """ + Test a successful, expected api response for the metadata fetch endpoint + """ + url = reverse( + 'api:v1:content-metadata-detail', + kwargs={'pk': self.content_metadata_object.id} + ) + response = self.client.get(url) + response_json = response.json() + assert response_json.get('title') == self.content_metadata_object.json_metadata.get('title') diff --git a/enterprise_catalog/apps/api/v1/urls.py b/enterprise_catalog/apps/api/v1/urls.py index 351effbe3..ff112d52e 100644 --- a/enterprise_catalog/apps/api/v1/urls.py +++ b/enterprise_catalog/apps/api/v1/urls.py @@ -14,6 +14,9 @@ from enterprise_catalog.apps.api.v1.views.catalog_workbook import ( CatalogWorkbookView, ) +from enterprise_catalog.apps.api.v1.views.content_metadata import ( + ContentMetadataView, +) from enterprise_catalog.apps.api.v1.views.curation.highlights import ( EnterpriseCurationConfigReadOnlyViewSet, EnterpriseCurationConfigViewSet, @@ -57,6 +60,7 @@ router.register(r'highlight-sets', HighlightSetReadOnlyViewSet, basename='highlight-sets') router.register(r'highlight-sets-admin', HighlightSetViewSet, basename='highlight-sets-admin') router.register(r'academies', AcademiesReadOnlyViewSet, basename='academies') +router.register(r'content-metadata', ContentMetadataView, basename='content-metadata') urlpatterns = [ path('enterprise-catalogs/catalog_csv_data', CatalogCsvDataView.as_view(), diff --git a/enterprise_catalog/apps/api/v1/views/content_metadata.py b/enterprise_catalog/apps/api/v1/views/content_metadata.py new file mode 100644 index 000000000..59b5e28f6 --- /dev/null +++ b/enterprise_catalog/apps/api/v1/views/content_metadata.py @@ -0,0 +1,35 @@ +from edx_rest_framework_extensions.auth.jwt.authentication import ( + JwtAuthentication, +) +from rest_framework import permissions, viewsets +from rest_framework.authentication import SessionAuthentication +from rest_framework.renderers import JSONRenderer +from rest_framework_xml.renderers import XMLRenderer + +from enterprise_catalog.apps.api.v1.pagination import ( + PageNumberWithSizePagination, +) +from enterprise_catalog.apps.api.v1.serializers import ContentMetadataSerializer +from enterprise_catalog.apps.catalog.models import ContentMetadata + + +class ContentMetadataView(viewsets.ReadOnlyModelViewSet): + """ + View for retrieving and listing base content metadata. + """ + serializer_class = ContentMetadataSerializer + authentication_classes = [JwtAuthentication, SessionAuthentication] + permission_classes = [permissions.IsAuthenticated] + renderer_classes = [JSONRenderer, XMLRenderer] + queryset = ContentMetadata.objects.all() + pagination_class = PageNumberWithSizePagination + + def get_queryset(self, **kwargs): + """ + Returns all content metadata objects filtered by an optional request query param ``content_keys`` (LIST). + """ + content_filter = kwargs.get('content_keys') + queryset = self.queryset + if content_filter: + return queryset.filter(content_key__in=content_filter) + return queryset diff --git a/enterprise_catalog/apps/catalog/tests/factories.py b/enterprise_catalog/apps/catalog/tests/factories.py index 9b4962ff2..9d9504772 100644 --- a/enterprise_catalog/apps/catalog/tests/factories.py +++ b/enterprise_catalog/apps/catalog/tests/factories.py @@ -101,6 +101,32 @@ def json_metadata(self): 'is_enrollable': True, 'is_marketable': True, 'availability': 'current', + 'seats': [ + { + 'type': 'audit', + 'price': '0.00', + 'currency': 'USD', + 'upgrade_deadline': None, + 'upgrade_deadline_override': None, + 'credit_provider': None, + 'credit_hours': None, + 'sku': '175338C', + 'bulk_sku': None + }, + { + 'type': 'verified', + 'price': '50.00', + 'currency': 'USD', + 'upgrade_deadline': '2026-01-26T23:59:59Z', + 'upgrade_deadline_override': None, + 'credit_provider': None, + 'credit_hours': None, + 'sku': 'F46BB55', + 'bulk_sku': 'C72C608' + } + ], + 'start': '2024-02-12T11:00:00Z', + 'end': '2026-02-05T11:00:00Z', }] json_metadata.update({ 'content_type': COURSE,