diff --git a/lms/djangoapps/commerce/api/v1/models.py b/lms/djangoapps/commerce/api/v1/models.py index 21a24b4ab4..e956cfa370 100644 --- a/lms/djangoapps/commerce/api/v1/models.py +++ b/lms/djangoapps/commerce/api/v1/models.py @@ -107,8 +107,20 @@ class Course(object): merged_modes.add(merged_mode) merged_mode_keys.add(merged_mode.mode_slug) - deleted_modes = set(existing_modes.keys()) - merged_mode_keys - self._deleted_modes = [existing_modes[mode] for mode in deleted_modes] + # Masters degrees are not sold through the eCommerce site. + # So, Masters course modes are not included in PUT calls to this API, + # and their omission which would normally cause them to be deleted. + # We don't want that to happen, but for the time being, + # we cannot include in Masters modes in the PUT calls from eCommerce. + # So, here's hack to handle Masters course modes, along with any other + # modes that end up in that boat. + MODES_TO_NOT_DELETE = { + CourseMode.MASTERS, + } + + modes_to_delete = set(existing_modes.keys()) - merged_mode_keys + modes_to_delete -= MODES_TO_NOT_DELETE + self._deleted_modes = [existing_modes[mode] for mode in modes_to_delete] self.modes = list(merged_modes) @classmethod diff --git a/lms/djangoapps/commerce/api/v1/permissions.py b/lms/djangoapps/commerce/api/v1/permissions.py index 1b5b41792d..019e111a02 100644 --- a/lms/djangoapps/commerce/api/v1/permissions.py +++ b/lms/djangoapps/commerce/api/v1/permissions.py @@ -24,6 +24,6 @@ class IsAuthenticatedOrActivationOverridden(BasePermission): if not request.user.is_authenticated and is_account_activation_requirement_disabled(): try: request.user = User.objects.get(id=request.session._session_cache['_auth_user_id']) - except DoesNotExist: + except User.DoesNotExist: pass return request.user.is_authenticated diff --git a/lms/djangoapps/commerce/api/v1/tests/test_views.py b/lms/djangoapps/commerce/api/v1/tests/test_views.py index a23cc7506c..ad2e7c2cac 100644 --- a/lms/djangoapps/commerce/api/v1/tests/test_views.py +++ b/lms/djangoapps/commerce/api/v1/tests/test_views.py @@ -287,25 +287,45 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase) self.assertIsNone(updated_verified_mode.expiration_datetime) def test_update_overwrite(self): - """ Verify that data submitted via PUT overwrites/deletes modes that are - not included in the body of the request. """ - course_id = six.text_type(self.course.id) - expected_course_mode = CourseMode( + """ + Verify that data submitted via PUT overwrites/deletes modes that are + not included in the body of the request, EXCEPT the Masters mode, + which it leaves alone. + """ + existing_mode = self.course_mode + existing_masters_mode = CourseMode.objects.create( + course_id=self.course.id, + mode_slug=u'masters', + min_price=10000, + currency=u'USD', + sku=u'DEF456', + bulk_sku=u'BULK-DEF456' + ) + new_mode = CourseMode( + course_id=self.course.id, mode_slug=u'credit', min_price=500, currency=u'USD', sku=u'ABC123', bulk_sku=u'BULK-ABC123' ) - expected = self._serialize_course(self.course, [expected_course_mode]) - path = reverse('commerce_api:v1:courses:retrieve_update', args=[course_id]) - response = self.client.put(path, json.dumps(expected), content_type=JSON_CONTENT_TYPE) - self.assertEqual(response.status_code, 200) - actual = json.loads(response.content) - self.assertEqual(actual, expected) - # The existing CourseMode should have been removed. - self.assertFalse(CourseMode.objects.filter(id=self.course_mode.id).exists()) + path = reverse('commerce_api:v1:courses:retrieve_update', args=[six.text_type(self.course.id)]) + data = json.dumps(self._serialize_course(self.course, [new_mode])) + response = self.client.put(path, data, content_type=JSON_CONTENT_TYPE) + self.assertEqual(response.status_code, 200) + + # Check modes list in response, disregarding its order. + expected_dict = self._serialize_course(self.course, [new_mode]) + expected_items = expected_dict['modes'] + actual_items = json.loads(response.content)['modes'] + self.assertCountEqual(actual_items, expected_items) + + # The existing non-Masters CourseMode should have been removed. + self.assertFalse(CourseMode.objects.filter(id=existing_mode.id).exists()) + + # The existing Masters course mode should remain. + self.assertTrue(CourseMode.objects.filter(id=existing_masters_mode.id).exists()) @ddt.data(*itertools.product( ('honor', 'audit', 'verified', 'professional', 'no-id-professional'),