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
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# 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()
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
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)
|
||||
65
lms/djangoapps/course_home_api/course_metadata/v1/views.py
Normal file
65
lms/djangoapps/course_home_api/course_metadata/v1/views.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
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)
|
||||
0
lms/djangoapps/course_home_api/dates/__init__.py
Normal file
0
lms/djangoapps/course_home_api/dates/__init__.py
Normal file
@@ -1,3 +1,4 @@
|
||||
# pylint: disable=abstract-method
|
||||
"""
|
||||
Dates Tab Serializers. Represents the relevant dates for a Course.
|
||||
"""
|
||||
|
||||
@@ -56,7 +56,9 @@ class DatesTabView(RetrieveAPIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
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
|
||||
monitoring_utils.set_custom_metric('course_id', course_key_string)
|
||||
monitoring_utils.set_custom_metric('user_id', request.user.id)
|
||||
|
||||
@@ -40,7 +40,7 @@ class BaseCourseHomeTests(SharedModuleStoreTestCase):
|
||||
modulestore=cls.store,
|
||||
)
|
||||
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(
|
||||
|
||||
@@ -6,15 +6,25 @@ Contains all the URLs for the Course Home
|
||||
from django.conf import settings
|
||||
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 = []
|
||||
|
||||
# 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
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r'v1/dates/{}'.format(settings.COURSE_KEY_PATTERN),
|
||||
views.DatesTabView.as_view(),
|
||||
DatesTabView.as_view(),
|
||||
name='course-home-dates-tab'
|
||||
),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user