Skip to content

Commit

Permalink
feat: ENT-7553 Added Academies api for MFEs
Browse files Browse the repository at this point in the history
  • Loading branch information
IrfanUddinAhmad committed Nov 18, 2023
1 parent def14ed commit 7065254
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 0 deletions.
58 changes: 58 additions & 0 deletions enterprise_catalog/apps/academy/tests/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from uuid import uuid4

import factory
from factory.fuzzy import FuzzyText

from enterprise_catalog.apps.academy.models import Academy, Tag
from enterprise_catalog.apps.catalog.tests.factories import (
EnterpriseCatalogFactory,
)


class TagFactory(factory.django.DjangoModelFactory):
"""
Test factory for the `Tag` model
"""
class Meta:
model = Tag


class AcademyFactory(factory.django.DjangoModelFactory):
"""
Test factory for the `Academy` model
"""
class Meta:
model = Academy

uuid = factory.LazyFunction(uuid4)
title = FuzzyText(length=32)
short_description = FuzzyText(length=32)
long_description = FuzzyText(length=255)

@factory.post_generation
def enterprise_catalogs(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return

if extracted:
for enterprise_catalog in extracted:
self.enterprise_catalogs.add(enterprise_catalog) # pylint: disable=no-member
else:
enterprise_catalog1 = EnterpriseCatalogFactory()
enterprise_catalog2 = EnterpriseCatalogFactory()
self.enterprise_catalogs.set([enterprise_catalog1, enterprise_catalog2]) # pylint: disable=no-member

@factory.post_generation
def tags(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return

if extracted:
for tag in extracted:
self.tags.add(tag) # pylint: disable=no-member
else:
tag1 = TagFactory()
tag2 = TagFactory()
self.tags.set([tag1, tag2]) # pylint: disable=no-member
23 changes: 23 additions & 0 deletions enterprise_catalog/apps/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.db import IntegrityError, models
from rest_framework import serializers, status

from enterprise_catalog.apps.academy.models import Academy, Tag
from enterprise_catalog.apps.api.v1.utils import (
get_enterprise_utm_context,
get_most_recent_modified_time,
Expand Down Expand Up @@ -392,3 +393,25 @@ def get_highlight_sets(self, obj):
}
for highlight_set in catalog_highlight_sets
]


class TagsSerializer(serializers.ModelSerializer):
"""
Serializer for the `Tag` model.
"""
class Meta:
model = Tag
fields = '__all__'


class AcademySerializer(serializers.ModelSerializer):
"""
Serializer for the `Academy` model.
"""
enterprise_catalogs = EnterpriseCatalogSerializer(many=True)
tags = TagsSerializer(many=True)

class Meta:
model = Academy
fields = '__all__'
lookup_field = 'uuid'
53 changes: 53 additions & 0 deletions enterprise_catalog/apps/api/v1/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
import pytz
from django.conf import settings
from django.db import IntegrityError
from django.utils.http import urlencode
from django.utils.text import slugify
from rest_framework import status
from rest_framework.reverse import reverse
from rest_framework.settings import api_settings
from six.moves.urllib.parse import quote_plus

from enterprise_catalog.apps.academy.tests.factories import AcademyFactory
from enterprise_catalog.apps.api.v1.serializers import ContentMetadataSerializer
from enterprise_catalog.apps.api.v1.tests.mixins import APITestMixin
from enterprise_catalog.apps.api.v1.utils import is_any_course_run_active
Expand Down Expand Up @@ -2312,3 +2314,54 @@ def test_content_metadata_delete_not_implemented(self):
"""
response = self.client.delete(urljoin(self.url, f"{self.content_key_1}/"))
assert response.status_code == 405


@ddt.ddt
class AcademiesViewSetTests(APITestMixin):
"""
Tests for the AcademyViewSet.
"""
def setUp(self):
super().setUp()
self.set_up_catalog_learner()
self.academy1 = AcademyFactory()
self.academy2 = AcademyFactory()
self.enterprise_catalog_query = CatalogQueryFactory(uuid=uuid.uuid4())
self.enterprise_catalog1 = EnterpriseCatalogFactory(catalog_query=self.enterprise_catalog_query)
self.enterprise_catalog1.academies.add(self.academy1)
self.enterprise_catalog2 = EnterpriseCatalogFactory(catalog_query=self.enterprise_catalog_query)
self.enterprise_catalog2.academies.add(self.academy2)

def test_list_for_academies(self):
"""
Verify the viewset returns enterprise specific academies
"""
params = {
'enterprise_customer': str(self.enterprise_catalog2.enterprise_customer.uuid)
}
url = reverse('api:v1:academies-list') + '?{}'.format(urlencode(params))
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 1)
results = response.data['results']
self.assertEqual(uuid.UUID(results[0]['uuid']), self.academy2.uuid)

def test_retrieve_for_academies(self):
"""
Verify the viewset retrieves an academy
"""
url = reverse('api:v1:academies-detail', kwargs={
'uuid': self.academy2.uuid,
})
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(uuid.UUID(response.data['uuid']), self.academy2.uuid)

def test_list_with_missing_enterprise_customer(self):
"""
Verify the viewset returns no records when enterprise customer is missing in params
"""
url = reverse('api:v1:academies-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 0)
10 changes: 10 additions & 0 deletions enterprise_catalog/apps/api/v1/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from django.urls import path, re_path
from rest_framework.routers import DefaultRouter

from enterprise_catalog.apps.api.v1.views.academies import (
AcademiesReadOnlyViewSet,
)
from enterprise_catalog.apps.api.v1.views.catalog_csv import CatalogCsvView
from enterprise_catalog.apps.api.v1.views.catalog_csv_data import (
CatalogCsvDataView,
Expand Down Expand Up @@ -53,6 +56,7 @@
router.register(r'enterprise-curations-admin', EnterpriseCurationConfigViewSet, basename='enterprise-curations-admin')
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')

urlpatterns = [
path('enterprise-catalogs/catalog_csv_data', CatalogCsvDataView.as_view(),
Expand All @@ -67,6 +71,12 @@
path('enterprise-catalogs/catalog_workbook', CatalogWorkbookView.as_view(),
name='catalog-workbook'
),
path('academies', AcademiesReadOnlyViewSet.as_view({'get': 'list'}),
name='academies-list'
),
path('academies/<uuid:uuid>/', AcademiesReadOnlyViewSet.as_view({'get': 'retrieve'}),
name='academies-detail'
),
re_path(
r'^enterprise-catalogs/(?P<uuid>[\S]+)/get_content_metadata',
EnterpriseCatalogGetContentMetadata.as_view({'get': 'get'}),
Expand Down
46 changes: 46 additions & 0 deletions enterprise_catalog/apps/api/v1/views/academies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from django.utils.functional import cached_property
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.academy.models import Academy
from enterprise_catalog.apps.api.v1.serializers import AcademySerializer


class AcademiesReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
""" Viewset for Read Only operations on Academies """
authentication_classes = [JwtAuthentication, SessionAuthentication]
permission_classes = [permissions.IsAuthenticated]
renderer_classes = [JSONRenderer, XMLRenderer]
serializer_class = AcademySerializer
lookup_field = 'uuid'

@cached_property
def request_action(self):
return getattr(self, 'action', None)

def get_queryset(self):
"""
Returns the queryset corresponding to all academies the requesting user has access to.
"""
enterprise_customer = self.request.GET.get('enterprise_customer', False)
all_academies = Academy.objects.all()
if self.request_action == 'list':
if enterprise_customer:
user_accessible_academy_uuids = []
for academy in all_academies:
academy_associated_catalogs = academy.enterprise_catalogs.all()
enterprise_associated_catalogs = academy_associated_catalogs.filter(
enterprise_uuid=enterprise_customer
)
if enterprise_associated_catalogs:
user_accessible_academy_uuids.append(academy.uuid)
return all_academies.filter(uuid__in=user_accessible_academy_uuids)
else:
return Academy.objects.none()

return Academy.objects.all()

0 comments on commit 7065254

Please sign in to comment.