diff --git a/lms/djangoapps/course_home_api/outline/v1/serializers.py b/lms/djangoapps/course_home_api/outline/v1/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..9222c98a10015cbdc1e0877ca11216a9eeb156f3 --- /dev/null +++ b/lms/djangoapps/course_home_api/outline/v1/serializers.py @@ -0,0 +1,28 @@ +""" +Outline Tab Serializers. +""" + + +from rest_framework import serializers + + +class CourseToolSerializer(serializers.Serializer): + """ + Serializer for Course Tool Objects + """ + analytics_id = serializers.CharField() + title = serializers.CharField() + url = serializers.SerializerMethodField() + + def get_url(self, tool): + course_key = self.context.get('course_key') + url = tool.url(course_key) + request = self.context.get('request') + return request.build_absolute_uri(url) + + +class OutlineTabSerializer(serializers.Serializer): + """ + Serializer for the Outline Tab + """ + course_tools = CourseToolSerializer(many=True) diff --git a/lms/djangoapps/course_home_api/outline/v1/tests/__init__.py b/lms/djangoapps/course_home_api/outline/v1/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lms/djangoapps/course_home_api/outline/v1/tests/test_views.py b/lms/djangoapps/course_home_api/outline/v1/tests/test_views.py new file mode 100644 index 0000000000000000000000000000000000000000..d3c3a92918c79dfedbff4380ecc771228e7572fc --- /dev/null +++ b/lms/djangoapps/course_home_api/outline/v1/tests/test_views.py @@ -0,0 +1,48 @@ +""" +Tests for Outline Tab API in the Course Home API +""" + + +import ddt + +from django.urls import reverse + +from course_modes.models import CourseMode +from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests +from student.models import CourseEnrollment + + +@ddt.ddt +class OutlineTabTestViews(BaseCourseHomeTests): + """ + Tests for the Outline Tab API + """ + @classmethod + def setUpClass(cls): + BaseCourseHomeTests.setUpClass() + cls.url = reverse('course-home-outline-tab', args=[cls.course.id]) + + @ddt.data(CourseMode.AUDIT, CourseMode.VERIFIED) + def test_get_authenticated_enrolled_user(self, enrollment_mode): + CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + + course_tools = response.data.get('course_tools') + self.assertTrue(course_tools) + self.assertEquals(course_tools[0]['analytics_id'], 'edx.bookmarks') + + def test_get_authenticated_user_not_enrolled(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertFalse(response.data.get('learner_is_verified')) + + course_tools = response.data.get('course_tools') + self.assertEqual(len(course_tools), 0) + + def test_get_unauthenticated_user(self): + self.client.logout() + response = self.client.get(self.url) + self.assertEqual(response.status_code, 403) + + # TODO: write test_get_unknown_course when more data is pulled into the Outline Tab API diff --git a/lms/djangoapps/course_home_api/outline/v1/views.py b/lms/djangoapps/course_home_api/outline/v1/views.py new file mode 100644 index 0000000000000000000000000000000000000000..5d4419403e7a110864e44b65c81056e4de1809a3 --- /dev/null +++ b/lms/djangoapps/course_home_api/outline/v1/views.py @@ -0,0 +1,63 @@ +""" +Outline Tab Views +""" + + +from rest_framework.generics import RetrieveAPIView +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response + +from edx_django_utils import monitoring as monitoring_utils +from opaque_keys.edx.keys import CourseKey + +from lms.djangoapps.course_home_api.outline.v1.serializers import OutlineTabSerializer +from openedx.features.course_experience.course_tools import CourseToolsPluginManager + + +class OutlineTabView(RetrieveAPIView): + """ + **Use Cases** + + Request details for the Outline Tab + + **Example Requests** + + GET api/course_home/v1/outline/{course_key} + + **Response Values** + + Body consists of the following fields: + + course_tools: List of serialized Course Tool objects. Each serialization has the following fields: + analytics_id: (str) The unique id given to the tool + title: (str) The display title of the tool + url: (str) The link to access the tool + + **Returns** + + * 200 on success with above fields. + * 403 if the user is not authenticated. + * 404 if the course is not available or cannot be seen. + + """ + + permission_classes = (IsAuthenticated,) + serializer_class = OutlineTabSerializer + + def get(self, request, course_key_string): + # Enable NR tracing for this view based on course + monitoring_utils.set_custom_metric('course_id', course_key_string) + monitoring_utils.set_custom_metric('user_id', request.user.id) + monitoring_utils.set_custom_metric('is_staff', request.user.is_staff) + + course_key = CourseKey.from_string(course_key_string) + course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) + + data = { + 'course_tools': course_tools, + } + context = self.get_serializer_context() + context['course_key'] = course_key + serializer = self.get_serializer_class()(data, context=context) + + return Response(serializer.data) diff --git a/lms/djangoapps/course_home_api/urls.py b/lms/djangoapps/course_home_api/urls.py index 1ee86db909739111c4512b43e284c9cca2e2f1ac..f5e3f94e6341f0ccf231fe9c614c06bd0bea823e 100644 --- a/lms/djangoapps/course_home_api/urls.py +++ b/lms/djangoapps/course_home_api/urls.py @@ -8,6 +8,7 @@ from django.urls import re_path from lms.djangoapps.course_home_api.dates.v1.views import DatesTabView from lms.djangoapps.course_home_api.course_metadata.v1.views import CourseHomeMetadataView +from lms.djangoapps.course_home_api.outline.v1.views import OutlineTabView urlpatterns = [] @@ -28,3 +29,12 @@ urlpatterns += [ name='course-home-dates-tab' ), ] + +# Outline Tab URLs +urlpatterns += [ + re_path( + r'v1/outline/{}'.format(settings.COURSE_KEY_PATTERN), + OutlineTabView.as_view(), + name='course-home-outline-tab' + ), +]