diff --git a/lms/djangoapps/course_home_api/dates/v1/serializers.py b/lms/djangoapps/course_home_api/dates/v1/serializers.py index 0f40993f93..d8162527f9 100644 --- a/lms/djangoapps/course_home_api/dates/v1/serializers.py +++ b/lms/djangoapps/course_home_api/dates/v1/serializers.py @@ -41,8 +41,5 @@ class DatesTabSerializer(DatesBannerSerializerMixin, serializers.Serializer): Serializer for the Dates Tab """ course_date_blocks = DateSummarySerializer(many=True) - missed_deadlines = serializers.BooleanField() - missed_gated_content = serializers.BooleanField() learner_is_full_access = serializers.BooleanField() user_timezone = serializers.CharField() - verified_upgrade_link = serializers.URLField() diff --git a/lms/djangoapps/course_home_api/dates/v1/views.py b/lms/djangoapps/course_home_api/dates/v1/views.py index b3c289b7e1..4fd19e5507 100644 --- a/lms/djangoapps/course_home_api/dates/v1/views.py +++ b/lms/djangoapps/course_home_api/dates/v1/views.py @@ -15,7 +15,7 @@ from opaque_keys.edx.keys import CourseKey from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_with_access -from lms.djangoapps.courseware.date_summary import TodaysDate, verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import TodaysDate from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.course_home_api.dates.v1.serializers import DatesTabSerializer from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active @@ -91,7 +91,6 @@ class DatesTabView(RetrieveAPIView): ) blocks = get_course_date_blocks(course, request.user, request, include_access=True, include_past_dates=True) - missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user) learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, @@ -105,11 +104,8 @@ class DatesTabView(RetrieveAPIView): data = { 'has_ended': course.has_ended(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], - 'missed_deadlines': missed_deadlines, - 'missed_gated_content': missed_gated_content, 'learner_is_full_access': learner_is_full_access, 'user_timezone': user_timezone, - 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), } context = self.get_serializer_context() context['learner_is_full_access'] = learner_is_full_access diff --git a/lms/djangoapps/course_home_api/mixins.py b/lms/djangoapps/course_home_api/mixins.py index ab3111fd14..2483a68b44 100644 --- a/lms/djangoapps/course_home_api/mixins.py +++ b/lms/djangoapps/course_home_api/mixins.py @@ -40,6 +40,5 @@ class DatesBannerSerializerMixin(serializers.Serializer): 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) + info['verified_upgrade_link'] = verified_upgrade_deadline_link(request.user, course_id=course_key) return info diff --git a/openedx/features/course_experience/api/v1/serializers.py b/openedx/features/course_experience/api/v1/serializers.py new file mode 100644 index 0000000000..24f2670135 --- /dev/null +++ b/openedx/features/course_experience/api/v1/serializers.py @@ -0,0 +1,8 @@ +""" +Serializer for Course Deadlines (Mobile) +""" +from lms.djangoapps.course_home_api.mixins import DatesBannerSerializerMixin + + +class CourseDeadlinesMobileSerializer(DatesBannerSerializerMixin): + pass diff --git a/openedx/features/course_experience/api/v1/tests/test_views.py b/openedx/features/course_experience/api/v1/tests/test_views.py index 4185ab7a41..fdd208ee76 100644 --- a/openedx/features/course_experience/api/v1/tests/test_views.py +++ b/openedx/features/course_experience/api/v1/tests/test_views.py @@ -34,3 +34,21 @@ class ResetCourseDeadlinesViewTests(BaseCourseHomeTests): self.client.logout() response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id}) self.assertEqual(response.status_code, 401) + + def test_mobile_get_banner_info(self): + response = self.client.get(reverse('course-experience-course-deadlines-mobile', args=[self.course.id])) + 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') + + def test_mobile_get_unknown_course(self): + url = reverse('course-experience-course-deadlines-mobile', args=['course-v1:unknown+course+2T2020']) + response = self.client.get(url) + self.assertEqual(response.status_code, 404) + + def test_mobile_get_unauthenticated_user(self): + self.client.logout() + response = self.client.get(reverse('course-experience-course-deadlines-mobile', args=[self.course.id])) + self.assertEqual(response.status_code, 401) diff --git a/openedx/features/course_experience/api/v1/urls.py b/openedx/features/course_experience/api/v1/urls.py index 66ca7c43c2..575ddfdb3f 100644 --- a/openedx/features/course_experience/api/v1/urls.py +++ b/openedx/features/course_experience/api/v1/urls.py @@ -3,9 +3,10 @@ Contains URLs for the Course Experience API """ +from django.conf import settings from django.urls import re_path -from openedx.features.course_experience.api.v1.views import reset_course_deadlines +from openedx.features.course_experience.api.v1.views import reset_course_deadlines, CourseDeadlinesMobileView urlpatterns = [] @@ -17,3 +18,12 @@ urlpatterns += [ name='course-experience-reset-course-deadlines' ), ] + +# URL for retrieving course deadlines info +urlpatterns += [ + re_path( + r'v1/course_deadlines_info/{}'.format(settings.COURSE_KEY_PATTERN), + CourseDeadlinesMobileView.as_view(), + name='course-experience-course-deadlines-mobile' + ), +] diff --git a/openedx/features/course_experience/api/v1/views.py b/openedx/features/course_experience/api/v1/views.py index f64ed576a4..e5055a60b9 100644 --- a/openedx/features/course_experience/api/v1/views.py +++ b/openedx/features/course_experience/api/v1/views.py @@ -2,12 +2,17 @@ from rest_framework.decorators import api_view, authentication_classes, permissi from rest_framework.exceptions import APIException, ParseError from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from rest_framework.generics import RetrieveAPIView from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser +from lms.djangoapps.courseware.courses import get_course_with_access + +from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser +from openedx.features.course_experience.api.v1.serializers import CourseDeadlinesMobileSerializer class UnableToResetDeadlines(APIException): @@ -37,3 +42,47 @@ def reset_course_deadlines(request): return Response({'message': 'Deadlines successfully reset.'}) except Exception: raise UnableToResetDeadlines + + +class CourseDeadlinesMobileView(RetrieveAPIView): + """ + **Use Cases** + + Request course deadline info for mobile + + **Example Requests** + + GET api/course_experience/v1/course_deadlines_info/{course_key} + + **Response Values** + + Body consists of the following fields: + + dates_banner_info: (obj) + missed_deadlines: (bool) Whether the user has missed any graded content deadlines for the given course. + missed_gated_content: (bool) Whether the user has missed any gated content for the given course. + content_type_gating_enabled: (bool) Whether content type gating is enabled for this enrollment. + verified_upgrade_link: (str) The URL to ecommerce IDA for purchasing the verified upgrade. + + **Returns** + + * 200 on success with above fields. + * 401 if the user is not authenticated. + * 404 if the course is not available or cannot be seen. + """ + + authentication_classes = ( + JwtAuthentication, + BearerAuthenticationAllowInactiveUser, + SessionAuthenticationAllowInactiveUser, + ) + permission_classes = (IsAuthenticated,) + serializer_class = CourseDeadlinesMobileSerializer + + def get(self, request, *args, **kwargs): + course_key_string = kwargs.get('course_key_string') + course_key = CourseKey.from_string(course_key_string) + get_course_with_access(request.user, 'load', course_key) + + serializer = self.get_serializer({}) + return Response(serializer.data)