From 7acff0a39e43353ff53ae8b129871816cd5cc44e Mon Sep 17 00:00:00 2001 From: "Albert St. Aubin" Date: Thu, 8 Mar 2018 13:45:54 -0500 Subject: [PATCH 1/2] correct check for enrollment on an entitlement [LEARNER-4484] --- openedx/core/djangoapps/catalog/utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openedx/core/djangoapps/catalog/utils.py b/openedx/core/djangoapps/catalog/utils.py index 6cea11d548..4cbefeda79 100644 --- a/openedx/core/djangoapps/catalog/utils.py +++ b/openedx/core/djangoapps/catalog/utils.py @@ -389,13 +389,17 @@ def get_fulfillable_course_runs_for_entitlement(entitlement, course_runs): search_time = datetime.datetime.now(UTC) for course_run in course_runs: course_id = CourseKey.from_string(course_run.get('key')) - is_enrolled = CourseEnrollment.is_enrolled(entitlement.user, course_id) + (user_enrollment_mode, is_active) = CourseEnrollment.enrollment_mode_for_user( + user=entitlement.user, + course_id=course_id + ) + is_enrolled_in_mode = user_enrollment_mode == entitlement.mode if is_course_run_entitlement_fulfillable(course_id, entitlement, search_time): - if (is_enrolled and + if (is_enrolled_in_mode and entitlement.enrollment_course_run and course_id == entitlement.enrollment_course_run.course_id): enrollable_sessions.append(course_run) - elif not is_enrolled: + elif not is_enrolled_in_mode: enrollable_sessions.append(course_run) enrollable_sessions.sort(key=lambda session: session.get('start')) From bd9fedb27b7c26033fe7fa039bf688eb70483959 Mon Sep 17 00:00:00 2001 From: "Albert St. Aubin" Date: Fri, 9 Mar 2018 09:48:33 -0500 Subject: [PATCH 2/2] corrected another enrollment edge case --- .../entitlements/api/v1/tests/test_views.py | 27 +++++++++++++++++++ .../djangoapps/entitlements/api/v1/views.py | 6 ++++- openedx/core/djangoapps/catalog/utils.py | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/common/djangoapps/entitlements/api/v1/tests/test_views.py b/common/djangoapps/entitlements/api/v1/tests/test_views.py index dca5862333..faf8742be4 100644 --- a/common/djangoapps/entitlements/api/v1/tests/test_views.py +++ b/common/djangoapps/entitlements/api/v1/tests/test_views.py @@ -490,6 +490,33 @@ class EntitlementEnrollmentViewSetTest(ModuleStoreTestCase): assert CourseEnrollment.is_enrolled(self.user, self.course.id) assert course_entitlement.enrollment_course_run is not None + @patch("entitlements.api.v1.views.get_course_runs_for_course") + def test_user_already_enrolled_in_unpaid_mode(self, mock_get_course_runs): + course_entitlement = CourseEntitlementFactory.create(user=self.user, mode=CourseMode.VERIFIED) + mock_get_course_runs.return_value = self.return_values + + url = reverse( + self.ENTITLEMENTS_ENROLLMENT_NAMESPACE, + args=[str(course_entitlement.uuid)] + ) + + CourseEnrollment.enroll(self.user, self.course.id, mode=CourseMode.AUDIT) + data = { + 'course_run_id': str(self.course.id) + } + response = self.client.post( + url, + data=json.dumps(data), + content_type='application/json', + ) + course_entitlement.refresh_from_db() + + assert response.status_code == 201 + assert CourseEnrollment.is_enrolled(self.user, self.course.id) + (enrolled_mode, is_active) = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id) + assert is_active and (enrolled_mode == course_entitlement.mode) + assert course_entitlement.enrollment_course_run is not None + @patch("entitlements.api.v1.views.get_course_runs_for_course") def test_user_cannot_enroll_in_unknown_course_run_id(self, mock_get_course_runs): fake_course_str = str(self.course.id) + 'fake' diff --git a/common/djangoapps/entitlements/api/v1/views.py b/common/djangoapps/entitlements/api/v1/views.py index 1fcffbf88f..7c62c482ce 100644 --- a/common/djangoapps/entitlements/api/v1/views.py +++ b/common/djangoapps/entitlements/api/v1/views.py @@ -21,6 +21,7 @@ from openedx.core.djangoapps.catalog.utils import get_course_runs_for_course from openedx.core.djangoapps.cors_csrf.authentication import SessionAuthenticationCrossDomainCsrf from student.models import CourseEnrollment from student.models import CourseEnrollmentException, AlreadyEnrolledError +from course_modes.models import CourseMode log = logging.getLogger(__name__) @@ -261,7 +262,10 @@ class EntitlementEnrollmentViewSet(viewsets.GenericViewSet): enrollment = CourseEnrollment.get_enrollment(user, course_run_key) if enrollment.mode == entitlement.mode: entitlement.set_enrollment(enrollment) - # Else the User is already enrolled in another Mode and we should + elif enrollment.mode not in [mode.slug for mode in CourseMode.paid_modes_for_course(course_run_key)]: + enrollment.update_enrollment(mode=entitlement.mode) + entitlement.set_enrollment(enrollment) + # Else the User is already enrolled in another paid Mode and we should # not do anything else related to Entitlements. except CourseEnrollmentException: message = ( diff --git a/openedx/core/djangoapps/catalog/utils.py b/openedx/core/djangoapps/catalog/utils.py index 4cbefeda79..68fee4459a 100644 --- a/openedx/core/djangoapps/catalog/utils.py +++ b/openedx/core/djangoapps/catalog/utils.py @@ -393,7 +393,7 @@ def get_fulfillable_course_runs_for_entitlement(entitlement, course_runs): user=entitlement.user, course_id=course_id ) - is_enrolled_in_mode = user_enrollment_mode == entitlement.mode + is_enrolled_in_mode = is_active and (user_enrollment_mode == entitlement.mode) if is_course_run_entitlement_fulfillable(course_id, entitlement, search_time): if (is_enrolled_in_mode and entitlement.enrollment_course_run and