Merge pull request #24122 from edx/ndalfonso/AA-133-mfe-dates-banner
AA-133 mfe dates banner
This commit is contained in:
@@ -35,3 +35,4 @@ class CourseHomeMetadataSerializer(serializers.Serializer):
|
||||
org = serializers.CharField()
|
||||
tabs = CourseTabSerializer(many=True)
|
||||
title = serializers.CharField()
|
||||
is_self_paced = serializers.BooleanField()
|
||||
|
||||
@@ -50,7 +50,6 @@ class CourseHomeMetadataView(RetrieveAPIView):
|
||||
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,
|
||||
@@ -58,6 +57,7 @@ class CourseHomeMetadataView(RetrieveAPIView):
|
||||
'org': course.display_org_with_default,
|
||||
'tabs': get_course_tab_list(request.user, course),
|
||||
'title': course.display_name_with_default,
|
||||
'is_self_paced': getattr(course, 'self_paced', False),
|
||||
}
|
||||
context = self.get_serializer_context()
|
||||
context['course'] = course
|
||||
|
||||
@@ -7,6 +7,7 @@ Dates Tab Serializers. Represents the relevant dates for a Course.
|
||||
from rest_framework import serializers
|
||||
|
||||
from lms.djangoapps.courseware.date_summary import VerificationDeadlineDate
|
||||
from lms.djangoapps.course_home_api.mixins import DatesBannerSerializerMixin
|
||||
|
||||
|
||||
class DateSummarySerializer(serializers.Serializer):
|
||||
@@ -33,7 +34,7 @@ class DateSummarySerializer(serializers.Serializer):
|
||||
return ''
|
||||
|
||||
|
||||
class DatesTabSerializer(serializers.Serializer):
|
||||
class DatesTabSerializer(DatesBannerSerializerMixin, serializers.Serializer):
|
||||
"""
|
||||
Serializer for the Dates Tab
|
||||
"""
|
||||
|
||||
@@ -56,3 +56,13 @@ class DatesTabTestViews(BaseCourseHomeTests):
|
||||
url = reverse('course-home-dates-tab', args=['course-v1:unknown+course+2T2020'])
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
@COURSE_HOME_MICROFRONTEND.override(active=True)
|
||||
@COURSE_HOME_MICROFRONTEND_DATES_TAB.override(active=True)
|
||||
def test_banner_data_is_returned(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'missed_deadlines')
|
||||
self.assertContains(response, 'missed_gated_content')
|
||||
self.assertContains(response, 'content_type_gating_enabled')
|
||||
self.assertContains(response, 'verified_upgrade_link')
|
||||
|
||||
45
lms/djangoapps/course_home_api/mixins.py
Normal file
45
lms/djangoapps/course_home_api/mixins.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# pylint: disable=abstract-method
|
||||
"""
|
||||
Course Home Mixins.
|
||||
"""
|
||||
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link
|
||||
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
|
||||
from openedx.features.course_experience.utils import dates_banner_should_display
|
||||
|
||||
|
||||
class DatesBannerSerializerMixin(serializers.Serializer):
|
||||
"""
|
||||
Serializer Mixin for displaying the dates banner.
|
||||
Can be added to any serializer who's tab wants to display it.
|
||||
"""
|
||||
dates_banner_info = serializers.SerializerMethodField()
|
||||
|
||||
def get_dates_banner_info(self, _):
|
||||
"""
|
||||
Serializer mixin for returning date banner info. Gets its input from
|
||||
the views course_key_string url parameter and the request's user object.
|
||||
"""
|
||||
info = {
|
||||
'missed_deadlines': False,
|
||||
'content_type_gating_enabled': False,
|
||||
}
|
||||
course_key_string = self.context['view'].kwargs.get('course_key_string')
|
||||
if course_key_string:
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
request = self.context['request']
|
||||
missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user)
|
||||
info['missed_deadlines'] = missed_deadlines
|
||||
info['missed_gated_content'] = missed_gated_content
|
||||
info['content_type_gating_enabled'] = ContentTypeGatingConfig.enabled_for_enrollment(
|
||||
user=request.user,
|
||||
course_key=course_key,
|
||||
)
|
||||
if info['content_type_gating_enabled']:
|
||||
info['verified_upgrade_link'] = verified_upgrade_deadline_link(request.user, course_id=course_key)
|
||||
return info
|
||||
@@ -963,3 +963,8 @@ urlpatterns.extend(plugin_urls.get_patterns(plugin_constants.ProjectType.LMS))
|
||||
urlpatterns += [
|
||||
url(r'^api/course_home/', include('lms.djangoapps.course_home_api.urls')),
|
||||
]
|
||||
|
||||
# Course Experience API urls
|
||||
urlpatterns += [
|
||||
url(r'^api/course_experience/', include('openedx.features.course_experience.api.v1.urls')),
|
||||
]
|
||||
|
||||
0
openedx/features/course_experience/api/__init__.py
Normal file
0
openedx/features/course_experience/api/__init__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
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 ResetCourseDeadlinesViewTests(BaseCourseHomeTests):
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
@ddt.data(CourseMode.VERIFIED)
|
||||
def test_reset_deadlines(self, enrollment_mode):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)
|
||||
# Test correct post body
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# Test body with incorrect body param
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course': self.course.id})
|
||||
self.assertEqual(response.status_code, 400)
|
||||
# Test body with additional incorrect body param
|
||||
response = self.client.post(
|
||||
reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id, 'invalid': 'value'}
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
19
openedx/features/course_experience/api/v1/urls.py
Normal file
19
openedx/features/course_experience/api/v1/urls.py
Normal file
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
Contains URLs for the Course Experience API
|
||||
"""
|
||||
|
||||
|
||||
from django.urls import re_path
|
||||
|
||||
from openedx.features.course_experience.api.v1.views import reset_course_deadlines
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
# URL for resetting course deadlines
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r'v1/reset_course_deadlines',
|
||||
reset_course_deadlines,
|
||||
name='course-experience-reset-course-deadlines'
|
||||
),
|
||||
]
|
||||
32
openedx/features/course_experience/api/v1/views.py
Normal file
32
openedx/features/course_experience/api/v1/views.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.exceptions import APIException, ParseError
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule
|
||||
|
||||
|
||||
class UnableToResetDeadlines(APIException):
|
||||
status_code = 400
|
||||
default_detail = 'Unable to reset deadlines.'
|
||||
default_code = 'unable_to_reset_deadlines'
|
||||
|
||||
|
||||
@permission_classes((IsAuthenticated,))
|
||||
@api_view(['POST'])
|
||||
def reset_course_deadlines(request):
|
||||
course_key = request.data.get('course_key', None)
|
||||
|
||||
# If body doesnt contain 'course_key', return 400 to client.
|
||||
if not course_key:
|
||||
raise ParseError("'course_key' is required.")
|
||||
|
||||
# If body contains params other than 'course_key', return 400 to client.
|
||||
if len(request.data) > 1:
|
||||
raise ParseError("Only 'course_key' is expected.")
|
||||
|
||||
try:
|
||||
reset_self_paced_schedule(request.user, course_key)
|
||||
return Response({'message': 'Deadlines successfully reset.'})
|
||||
except Exception:
|
||||
raise UnableToResetDeadlines
|
||||
Reference in New Issue
Block a user