Skip to content
Snippets Groups Projects
Unverified Commit 0a1745ab authored by Dillon Dumesnil's avatar Dillon Dumesnil Committed by GitHub
Browse files

Merge pull request #24054 from edx/ddumesnil/general-course-home-api-AA-150

AA-150: Adding an end point for Course Metadata in the Course Home MFE
parents 7738d625 8a74bbd5
No related branches found
No related tags found
No related merge requests found
Showing
with 172 additions and 4 deletions
# pylint: disable=abstract-method
"""
Course Home Course Metadata Serializers. Returns Course Metadata used for all
Course Home pages.
"""
from django.urls import reverse
from rest_framework import serializers
class CourseTabSerializer(serializers.Serializer):
"""
Serializer for the Course Home Tabs
"""
tab_id = serializers.CharField()
title = serializers.SerializerMethodField()
url = serializers.SerializerMethodField()
def get_title(self, tab):
return tab.title or tab.get('name', '')
def get_url(self, tab):
request = self.context.get('request')
return request.build_absolute_uri(tab.link_func(self.context.get('course'), reverse))
class CourseHomeMetadataSerializer(serializers.Serializer):
"""
Serializer for the Course Home Course Metadata
"""
course_id = serializers.CharField()
is_staff = serializers.BooleanField()
number = serializers.CharField()
org = serializers.CharField()
tabs = CourseTabSerializer(many=True)
title = serializers.CharField()
"""
Tests for the Course Home Course Metadata 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
from student.tests.factories import UserFactory
@ddt.ddt
class CourseHomeMetadataTests(BaseCourseHomeTests):
"""
Tests for the Course Home Course Metadata API
"""
@classmethod
def setUpClass(cls):
BaseCourseHomeTests.setUpClass()
cls.url = reverse('course-home-course-metadata', args=[cls.course.id])
def test_get_authenticated_user(self):
CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertFalse(response.data.get('is_staff'))
# 'Course', 'Wiki', 'Progress' tabs
self.assertEqual(len(response.data.get('tabs', [])), 3)
def test_get_authenticated_staff_user(self):
self.client.logout()
staff_user = UserFactory(
username='staff',
email='staff@example.com',
password='bar',
is_staff=True
)
self.client.login(username=staff_user.username, password='bar')
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertTrue(response.data['is_staff'])
# This differs for a staff user because they also receive the Instructor tab
# 'Course', 'Wiki', 'Progress', and 'Instructor' tabs
self.assertEqual(len(response.data.get('tabs', [])), 4)
def test_get_unknown_course(self):
url = reverse('course-home-course-metadata', args=['course-v1:unknown+course+2T2020'])
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
"""
General view for the Course Home that contains metadata every page needs.
"""
from rest_framework.generics import RetrieveAPIView
from rest_framework.response import Response
from opaque_keys.edx.keys import CourseKey
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.tabs import get_course_tab_list
from lms.djangoapps.course_api.api import course_detail
from lms.djangoapps.course_home_api.course_metadata.v1.serializers import CourseHomeMetadataSerializer
class CourseHomeMetadataView(RetrieveAPIView):
"""
**Use Cases**
Request Course metadata details for the Course Home MFE that every page needs.
**Example Requests**
GET api/course_home/v1/course_metadata/{course_key}
**Response Values**
Body consists of the following fields:
course_id: (str) The Course's id (Course Run key)
is_staff: (bool) Indicates if the user is staff
number: (str) The Course's number
org: (str) The Course's organization
tabs: List of Course Tabs to display. They are serialized as:
tab_id: (str) The tab's id
title: (str) The title of the tab to display
url: (str) The url to view the tab
title: (str) The Course's display title
**Returns**
* 200 on success with above fields.
* 404 if the course is not available or cannot be seen.
"""
serializer_class = CourseHomeMetadataSerializer
def get(self, request, *args, **kwargs):
course_key_string = kwargs.get('course_key_string')
course_key = CourseKey.from_string(course_key_string)
course = course_detail(request, request.user.username, course_key)
data = {
'course_id': course.id,
'is_staff': has_access(request.user, 'staff', course_key).has_access,
'number': course.display_number_with_default,
'org': course.display_org_with_default,
'tabs': get_course_tab_list(request.user, course),
'title': course.display_name_with_default,
}
context = self.get_serializer_context()
context['course'] = course
serializer = self.get_serializer_class()(data, context=context)
return Response(serializer.data)
# pylint: disable=abstract-method
""" """
Dates Tab Serializers. Represents the relevant dates for a Course. Dates Tab Serializers. Represents the relevant dates for a Course.
""" """
......
...@@ -56,7 +56,9 @@ class DatesTabView(RetrieveAPIView): ...@@ -56,7 +56,9 @@ class DatesTabView(RetrieveAPIView):
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
serializer_class = DatesTabSerializer serializer_class = DatesTabSerializer
def get(self, request, course_key_string): def get(self, request, *args, **kwargs):
course_key_string = kwargs.get('course_key_string')
# Enable NR tracing for this view based on course # Enable NR tracing for this view based on course
monitoring_utils.set_custom_metric('course_id', course_key_string) 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('user_id', request.user.id)
......
...@@ -40,7 +40,7 @@ class BaseCourseHomeTests(SharedModuleStoreTestCase): ...@@ -40,7 +40,7 @@ class BaseCourseHomeTests(SharedModuleStoreTestCase):
modulestore=cls.store, modulestore=cls.store,
) )
chapter = ItemFactory(parent=cls.course, category='chapter') chapter = ItemFactory(parent=cls.course, category='chapter')
ItemFactory(parent=chapter, category='sequential', display_name='sequence') ItemFactory(parent=chapter, category='sequential')
CourseModeFactory(course_id=cls.course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory(course_id=cls.course.id, mode_slug=CourseMode.AUDIT)
CourseModeFactory( CourseModeFactory(
......
...@@ -6,15 +6,25 @@ Contains all the URLs for the Course Home ...@@ -6,15 +6,25 @@ Contains all the URLs for the Course Home
from django.conf import settings from django.conf import settings
from django.urls import re_path from django.urls import re_path
from lms.djangoapps.course_home_api.dates.v1 import views from lms.djangoapps.course_home_api.dates.v1.views import DatesTabView
from lms.djangoapps.course_home_api.course_metadata.v1.views import CourseHomeMetadataView
urlpatterns = [] urlpatterns = []
# URL for Course metadata content
urlpatterns += [
re_path(
r'v1/course_metadata/{}'.format(settings.COURSE_KEY_PATTERN),
CourseHomeMetadataView.as_view(),
name='course-home-course-metadata'
),
]
# Dates Tab URLs # Dates Tab URLs
urlpatterns += [ urlpatterns += [
re_path( re_path(
r'v1/dates/{}'.format(settings.COURSE_KEY_PATTERN), r'v1/dates/{}'.format(settings.COURSE_KEY_PATTERN),
views.DatesTabView.as_view(), DatesTabView.as_view(),
name='course-home-dates-tab' name='course-home-dates-tab'
), ),
] ]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment