From b77b90a344c5aebb833b72cd815483d505f69d6b Mon Sep 17 00:00:00 2001 From: jawad khan Date: Wed, 24 Jul 2024 01:40:41 +0500 Subject: [PATCH] =?UTF-8?q?fix:=20Enable=20courseware=20access=20api=20for?= =?UTF-8?q?=20all=20types=20of=20course(expired,=20cl=E2=80=A6=20(#35155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Enable courseware access api for all types of course(expired, closed etc) --- .../mobile_api/course_info/views.py | 14 +++- .../tests/test_course_info_views.py | 79 +++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/lms/djangoapps/mobile_api/course_info/views.py b/lms/djangoapps/mobile_api/course_info/views.py index 0c4d4a96aa01..affefafe5ba0 100644 --- a/lms/djangoapps/mobile_api/course_info/views.py +++ b/lms/djangoapps/mobile_api/course_info/views.py @@ -418,19 +418,25 @@ class CourseEnrollmentDetailsView(APIView): This api works with all versions {api_version}, you can use: v0.5, v1, v2 or v3 - GET /api/mobile/{api_version}/course_info/{course_id}}/enrollment_details + GET /api/mobile/{api_version}/course_info/{course_id}/enrollment_details """ - @mobile_course_access() - def get(self, request, course, *args, **kwargs): + def get(self, request, *args, **kwargs): """ Handle the GET request Returns user enrollment and course details. """ + course_key_string = kwargs.get('course_id') + try: + course_key = CourseKey.from_string(course_key_string) + except InvalidKeyError: + error = {'error': f"'{str(course_key_string)}' is not a valid course key."} + return Response(data=error, status=status.HTTP_400_BAD_REQUEST) + data = { 'api_version': self.kwargs.get('api_version'), - 'course_id': course.id, + 'course_id': course_key, 'user': request.user, 'request': request, } diff --git a/lms/djangoapps/mobile_api/tests/test_course_info_views.py b/lms/djangoapps/mobile_api/tests/test_course_info_views.py index 730943c365e9..56c020ec8fa3 100644 --- a/lms/djangoapps/mobile_api/tests/test_course_info_views.py +++ b/lms/djangoapps/mobile_api/tests/test_course_info_views.py @@ -1,6 +1,7 @@ """ Tests for course_info """ +from datetime import datetime, timedelta from unittest.mock import patch import ddt @@ -11,6 +12,7 @@ from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag from milestones.tests.utils import MilestonesTestCaseMixin +from pytz import utc from rest_framework import status from common.djangoapps.student.tests.factories import UserFactory # pylint: disable=unused-import @@ -26,6 +28,7 @@ from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.tests.django_utils import \ SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order +from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.xml_importer import import_course_from_xml # lint-amnesty, pylint: disable=wrong-import-order User = get_user_model() @@ -521,3 +524,79 @@ def verify_certificate(self, response, mock_certificate_downloadable_status): mock_certificate_downloadable_status.assert_called_once() certificate_url = 'https://test_certificate_url' assert response.data['certificate'] == {'url': certificate_url} + + @patch('lms.djangoapps.mobile_api.course_info.utils.certificate_downloadable_status') + def test_course_not_started(self, mock_certificate_downloadable_status): + """ Test course data which has not started yet """ + + certificate_url = 'https://test_certificate_url' + mock_certificate_downloadable_status.return_value = { + 'is_downloadable': True, + 'download_url': certificate_url, + } + now = datetime.now(utc) + course_not_started = CourseFactory.create( + mobile_available=True, + static_asset_path="needed_for_split", + start=now + timedelta(days=5), + ) + + url = reverse('course-enrollment-details', kwargs={ + 'api_version': 'v1', + 'course_id': course_not_started.id + }) + + response = self.client.get(path=url) + assert response.status_code == 200 + assert response.data['id'] == str(course_not_started.id) + + self.verify_course_access_details(response) + + @patch('lms.djangoapps.mobile_api.course_info.utils.certificate_downloadable_status') + def test_course_closed(self, mock_certificate_downloadable_status): + """ Test course data whose end date is in past """ + + certificate_url = 'https://test_certificate_url' + mock_certificate_downloadable_status.return_value = { + 'is_downloadable': True, + 'download_url': certificate_url, + } + now = datetime.now(utc) + course_closed = CourseFactory.create( + mobile_available=True, + static_asset_path="needed_for_split", + start=now - timedelta(days=250), + end=now - timedelta(days=50), + ) + + url = reverse('course-enrollment-details', kwargs={ + 'api_version': 'v1', + 'course_id': course_closed.id + }) + + response = self.client.get(path=url) + assert response.status_code == 200 + assert response.data['id'] == str(course_closed.id) + + self.verify_course_access_details(response) + + @patch('lms.djangoapps.mobile_api.course_info.utils.certificate_downloadable_status') + def test_invalid_course_id(self, mock_certificate_downloadable_status): + """ Test view with invalid course id """ + + certificate_url = 'https://test_certificate_url' + mock_certificate_downloadable_status.return_value = { + 'is_downloadable': True, + 'download_url': certificate_url, + } + + invalid_id = "invalid" + str(self.course.id) + url = reverse('course-enrollment-details', kwargs={ + 'api_version': 'v1', + 'course_id': invalid_id + }) + + response = self.client.get(path=url) + assert response.status_code == 400 + expected_error = "'{}' is not a valid course key.".format(invalid_id) + assert response.data['error'] == expected_error