AA-150: Adding a general end point for the Course Home MFE
This endpoint is intended to contain generic information for every page in the Course Home MFE. It contains course information for the header (Course title, org, number, key) as well as staff status for the user and the Course tabs to display.
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