From 390122ec933f842182bfb88bcf2511e52f86df40 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 24 Jun 2019 14:23:08 -0400 Subject: [PATCH 1/5] Make CourseOverviewFactory create new courses every time (unless otherwise specified) --- common/djangoapps/student/tests/test_views.py | 2 +- .../djangoapps/content/course_overviews/tests/factories.py | 4 +++- .../schedules/management/commands/tests/send_email_base.py | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index ffeaa1db3b..42e34a54e9 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -516,7 +516,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, course_overview = CourseOverviewFactory( start=self.TOMORROW, self_paced=True, enrollment_end=self.TOMORROW ) - course_enrollment = CourseEnrollmentFactory(user=self.user) + course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=course_overview.id) entitlement = CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment) course_runs = [{ 'key': six.text_type(course_overview.id), diff --git a/openedx/core/djangoapps/content/course_overviews/tests/factories.py b/openedx/core/djangoapps/content/course_overviews/tests/factories.py index e898ff2b02..d344795275 100644 --- a/openedx/core/djangoapps/content/course_overviews/tests/factories.py +++ b/openedx/core/djangoapps/content/course_overviews/tests/factories.py @@ -13,10 +13,12 @@ class CourseOverviewFactory(DjangoModelFactory): class Meta(object): model = CourseOverview django_get_or_create = ('id', ) + exclude = ('run', ) version = CourseOverview.VERSION pre_requisite_courses = [] org = 'edX' + run = factory.Sequence('2012_Fall_{}'.format) @factory.lazy_attribute def _pre_requisite_courses_json(self): @@ -28,7 +30,7 @@ class CourseOverviewFactory(DjangoModelFactory): @factory.lazy_attribute def id(self): - return CourseLocator(self.org, 'toy', '2012_Fall') + return CourseLocator(self.org, 'toy', self.run) @factory.lazy_attribute def display_name(self): diff --git a/openedx/core/djangoapps/schedules/management/commands/tests/send_email_base.py b/openedx/core/djangoapps/schedules/management/commands/tests/send_email_base.py index 3eb6492499..e80dae6bda 100644 --- a/openedx/core/djangoapps/schedules/management/commands/tests/send_email_base.py +++ b/openedx/core/djangoapps/schedules/management/commands/tests/send_email_base.py @@ -139,6 +139,8 @@ class ScheduleSendEmailTestMixin(FilteredQueryCountMixin): factory_kwargs.setdefault('start', target_day) factory_kwargs.setdefault('upgrade_deadline', upgrade_deadline) factory_kwargs.setdefault('enrollment__course__self_paced', True) + # Make all schedules in the same course + factory_kwargs.setdefault('enrollment__course__run', '2012_Fall') if hasattr(self, 'experience_type'): factory_kwargs.setdefault('experience__experience_type', self.experience_type) schedule = ScheduleFactory(**factory_kwargs) From ac9ba2b95ac034395660cffdd42f2c1d5c46a660 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 24 Jun 2019 14:25:00 -0400 Subject: [PATCH 2/5] Only make users who haven't previously enrolled in a non-upsellable course eligible for the discount --- openedx/features/discounts/applicability.py | 6 +++++ .../discounts/tests/test_applicability.py | 26 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/openedx/features/discounts/applicability.py b/openedx/features/discounts/applicability.py index 4caa0a8d8b..3fa32ae920 100644 --- a/openedx/features/discounts/applicability.py +++ b/openedx/features/discounts/applicability.py @@ -11,6 +11,7 @@ not other discounts like coupons or enterprise/program offers configured in ecom from course_modes.models import CourseMode from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace from openedx.features.discounts.models import DiscountRestrictionConfig +from student.models import CourseEnrollment # .. feature_toggle_name: discounts.enable_discounting # .. feature_toggle_type: flag @@ -55,6 +56,11 @@ def can_receive_discount(user, course): # pylint: disable=unused-argument if DiscountRestrictionConfig.disabled_for_course_stacked_config(course): return False + # Don't allow users who have enrolled in any courses in non-upsellable + # modes + if CourseEnrollment.objects.filter(user=user).exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES).exists(): + return False + return True diff --git a/openedx/features/discounts/tests/test_applicability.py b/openedx/features/discounts/tests/test_applicability.py index b0e9a3bd88..160587003b 100644 --- a/openedx/features/discounts/tests/test_applicability.py +++ b/openedx/features/discounts/tests/test_applicability.py @@ -2,19 +2,22 @@ # -*- coding: utf-8 -*- from datetime import timedelta +import ddt from django.utils.timezone import now +from course_modes.models import CourseMode from course_modes.tests.factories import CourseModeFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag from openedx.features.discounts.models import DiscountRestrictionConfig -from student.tests.factories import UserFactory +from student.tests.factories import UserFactory, CourseEnrollmentFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from ..applicability import can_receive_discount, DISCOUNT_APPLICABILITY_FLAG +@ddt.ddt class TestApplicability(ModuleStoreTestCase): """ Applicability determines if this combination of user and course can receive a discount. Make @@ -54,3 +57,24 @@ class TestApplicability(ModuleStoreTestCase): DiscountRestrictionConfig.objects.create(disabled=True, course=disabled_course_overview) applicability = can_receive_discount(user=self.user, course=disabled_course) self.assertEqual(applicability, False) + + @ddt.data(*( + [[]] + + [[mode] for mode in CourseMode.ALL_MODES] + + [ + [mode1, mode2] + for mode1 in CourseMode.ALL_MODES + for mode2 in CourseMode.ALL_MODES + if mode1 != mode2 + ] + )) + @override_waffle_flag(DISCOUNT_APPLICABILITY_FLAG, active=True) + def test_can_receive_discount_previous_verified_enrollment(self, existing_enrollments): + """ + Ensure that only users who have not already purchased courses receive the discount. + """ + for mode in existing_enrollments: + CourseEnrollmentFactory.create(mode=mode, user=self.user) + + applicability = can_receive_discount(user=self.user, course=self.course) + assert applicability == all(mode in CourseMode.UPSELL_TO_VERIFIED_MODES for mode in existing_enrollments) From ce058aa5eea254bf61b24eb4f1acfa20218a26c8 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 24 Jun 2019 15:09:37 -0400 Subject: [PATCH 3/5] Only allow users who have no entitlements to receive discounts --- openedx/features/discounts/applicability.py | 5 +++++ .../discounts/tests/test_applicability.py | 17 +++++++++++++++++ openedx/tests/settings.py | 1 + 3 files changed, 23 insertions(+) diff --git a/openedx/features/discounts/applicability.py b/openedx/features/discounts/applicability.py index 3fa32ae920..0c2bb26ea1 100644 --- a/openedx/features/discounts/applicability.py +++ b/openedx/features/discounts/applicability.py @@ -9,6 +9,7 @@ not other discounts like coupons or enterprise/program offers configured in ecom """ from course_modes.models import CourseMode +from entitlements.models import CourseEntitlement from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace from openedx.features.discounts.models import DiscountRestrictionConfig from student.models import CourseEnrollment @@ -61,6 +62,10 @@ def can_receive_discount(user, course): # pylint: disable=unused-argument if CourseEnrollment.objects.filter(user=user).exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES).exists(): return False + # Don't allow any users who have entitlements (past or present) + if CourseEntitlement.objects.filter(user=user).exists(): + return False + return True diff --git a/openedx/features/discounts/tests/test_applicability.py b/openedx/features/discounts/tests/test_applicability.py index 160587003b..bd5c7d7e01 100644 --- a/openedx/features/discounts/tests/test_applicability.py +++ b/openedx/features/discounts/tests/test_applicability.py @@ -7,6 +7,7 @@ from django.utils.timezone import now from course_modes.models import CourseMode from course_modes.tests.factories import CourseModeFactory +from entitlements.tests.factories import CourseEntitlementFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag from openedx.features.discounts.models import DiscountRestrictionConfig @@ -78,3 +79,19 @@ class TestApplicability(ModuleStoreTestCase): applicability = can_receive_discount(user=self.user, course=self.course) assert applicability == all(mode in CourseMode.UPSELL_TO_VERIFIED_MODES for mode in existing_enrollments) + + @ddt.data( + None, + CourseMode.VERIFIED, + CourseMode.PROFESSIONAL, + ) + @override_waffle_flag(DISCOUNT_APPLICABILITY_FLAG, active=True) + def test_can_receive_discount_entitlement(self, entitlement_mode): + """ + Ensure that only users who have not already purchased courses receive the discount. + """ + if entitlement_mode is not None: + CourseEntitlementFactory.create(mode=entitlement_mode, user=self.user) + + applicability = can_receive_discount(user=self.user, course=self.course) + assert applicability == (entitlement_mode is None) diff --git a/openedx/tests/settings.py b/openedx/tests/settings.py index 4dd346c915..b31f7846e0 100644 --- a/openedx/tests/settings.py +++ b/openedx/tests/settings.py @@ -94,6 +94,7 @@ INSTALLED_APPS = ( # Django 1.11 demands to have imported models supported by installed apps. 'completion', + 'entitlements', ) LMS_ROOT_URL = "http://localhost:8000" From 388fac3b9c80eca48799751fc8bb10efad0a68df Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 25 Jun 2019 10:45:31 -0400 Subject: [PATCH 4/5] Make has_non_audit_enrollments exclude honor courses correctly --- .../tests/test_field_override_performance.py | 4 ++-- .../courseware/tests/test_course_info.py | 4 ++-- lms/djangoapps/courseware/tests/test_views.py | 12 +++++------ lms/djangoapps/experiments/utils.py | 20 +++++++++---------- .../tests/views/test_course_home.py | 2 +- .../tests/views/test_course_updates.py | 2 +- 6 files changed, 21 insertions(+), 23 deletions(-) diff --git a/lms/djangoapps/ccx/tests/test_field_override_performance.py b/lms/djangoapps/ccx/tests/test_field_override_performance.py index a376c16f4c..8127460f2c 100644 --- a/lms/djangoapps/ccx/tests/test_field_override_performance.py +++ b/lms/djangoapps/ccx/tests/test_field_override_performance.py @@ -244,7 +244,7 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase): __test__ = True # TODO: decrease query count as part of REVO-28 - QUERY_COUNT = 35 + QUERY_COUNT = 34 TEST_DATA = { # (providers, course_width, enable_ccx, view_as_ccx): ( # # of sql queries to default, @@ -273,7 +273,7 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase): __test__ = True # TODO: decrease query count as part of REVO-28 - QUERY_COUNT = 35 + QUERY_COUNT = 34 TEST_DATA = { ('no_overrides', 1, True, False): (QUERY_COUNT, 3), diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py index d8cb1f19e8..7b2504be48 100644 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ b/lms/djangoapps/courseware/tests/test_course_info.py @@ -434,8 +434,8 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest def test_num_queries_instructor_paced(self): # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.instructor_paced_course, 44, 3) + self.fetch_course_info_with_queries(self.instructor_paced_course, 43, 3) def test_num_queries_self_paced(self): # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.self_paced_course, 44, 3) + self.fetch_course_info_with_queries(self.self_paced_course, 43, 3) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 02dc769a5b..907ec26420 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -224,8 +224,8 @@ class IndexQueryTestCase(ModuleStoreTestCase): NUM_PROBLEMS = 20 @ddt.data( - (ModuleStoreEnum.Type.mongo, 10, 181), - (ModuleStoreEnum.Type.split, 4, 175), + (ModuleStoreEnum.Type.mongo, 10, 180), + (ModuleStoreEnum.Type.split, 4, 174), ) @ddt.unpack def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count): @@ -1466,8 +1466,8 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertContains(resp, u"Download Your Certificate") @ddt.data( - (True, 55), - (False, 54) + (True, 54), + (False, 53) ) @ddt.unpack def test_progress_queries_paced_courses(self, self_paced, query_count): @@ -1480,8 +1480,8 @@ class ProgressPageTests(ProgressPageBaseTests): @patch.dict(settings.FEATURES, {'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS': False}) @ddt.data( - (False, 63, 43), - (True, 54, 38) + (False, 62, 42), + (True, 53, 37) ) @ddt.unpack def test_progress_queries(self, enable_waffle, initial, subsequent): diff --git a/lms/djangoapps/experiments/utils.py b/lms/djangoapps/experiments/utils.py index 42c0fbae35..3ad809affd 100644 --- a/lms/djangoapps/experiments/utils.py +++ b/lms/djangoapps/experiments/utils.py @@ -14,7 +14,7 @@ from django.utils.timezone import now from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey -from course_modes.models import format_course_price, get_cosmetic_verified_display_price +from course_modes.models import format_course_price, get_cosmetic_verified_display_price, CourseMode from courseware.access import has_staff_access_to_preview_mode from courseware.date_summary import verified_upgrade_deadline_link, verified_upgrade_link_is_valid from lms.djangoapps.commerce.utils import EcommerceService @@ -236,14 +236,12 @@ def get_dashboard_course_info(user, dashboard_enrollments): if DASHBOARD_INFO_FLAG.is_enabled(): # Get the enrollments here since the dashboard filters out those with completed entitlements user_enrollments = CourseEnrollment.objects.select_related('course').filter(user_id=user.id) - audit_enrollments = user_enrollments.filter(mode='audit') course_info = { str(dashboard_enrollment.course): get_base_experiment_metadata_context(dashboard_enrollment.course, user, dashboard_enrollment, - user_enrollments, - audit_enrollments) + user_enrollments) for dashboard_enrollment in dashboard_enrollments } return course_info @@ -261,8 +259,7 @@ def get_experiment_user_metadata_context(course, user): has_non_audit_enrollments = False try: user_enrollments = CourseEnrollment.objects.select_related('course').filter(user_id=user.id) - audit_enrollments = user_enrollments.filter(mode='audit') - has_non_audit_enrollments = (len(audit_enrollments) != len(user_enrollments)) + has_non_audit_enrollments = user_enrollments.exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES).exists() # TODO: clean up as part of REVO-28 (END) enrollment = CourseEnrollment.objects.select_related( 'course' @@ -270,7 +267,7 @@ def get_experiment_user_metadata_context(course, user): except CourseEnrollment.DoesNotExist: pass # Not enrolled, use the default values - context = get_base_experiment_metadata_context(course, user, enrollment, user_enrollments, audit_enrollments) + context = get_base_experiment_metadata_context(course, user, enrollment, user_enrollments) has_staff_access = has_staff_access_to_preview_mode(user, course.id) forum_roles = [] if user.is_authenticated: @@ -292,14 +289,14 @@ def get_experiment_user_metadata_context(course, user): return context -def get_base_experiment_metadata_context(course, user, enrollment, user_enrollments, audit_enrollments): +def get_base_experiment_metadata_context(course, user, enrollment, user_enrollments): """ Return a context dictionary with the keys used by dashboard_metadata.html and user_metadata.html """ enrollment_mode = None enrollment_time = None # TODO: clean up as part of REVEM-199 (START) - program_key = get_program_context(course, user_enrollments, audit_enrollments) + program_key = get_program_context(course, user_enrollments) # TODO: clean up as part of REVEM-199 (END) if enrollment and enrollment.is_active: enrollment_mode = enrollment.mode @@ -336,11 +333,13 @@ def get_audit_access_expiration(user, course): # TODO: clean up as part of REVEM-199 (START) -def get_program_context(course, user_enrollments, audit_enrollments): +def get_program_context(course, user_enrollments): """ Return a context dictionary with program information. """ program_key = None + non_audit_enrollments = user_enrollments.exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES) + if PROGRAM_INFO_FLAG.is_enabled(): programs = get_programs(course=course.id) if programs: @@ -362,7 +361,6 @@ def get_program_context(course, user_enrollments, audit_enrollments): # program has 3 courses (A, B and C), and the user previously purchased a certificate for A. # The user is enrolled in audit mode for B. The "left to purchase price" should be the price of # B+C. - non_audit_enrollments = [en for en in user_enrollments if en not in audit_enrollments] courses_left_to_purchase = get_unenrolled_courses(courses, non_audit_enrollments) if courses_left_to_purchase: has_courses_left_to_purchase = True diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index b64d26645a..6238833d7e 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -218,7 +218,7 @@ class TestCourseHomePage(CourseHomePageTestCase): # Fetch the view and verify the query counts # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(94, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(93, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/openedx/features/course_experience/tests/views/test_course_updates.py b/openedx/features/course_experience/tests/views/test_course_updates.py index 45d51a5448..3f628b2b51 100644 --- a/openedx/features/course_experience/tests/views/test_course_updates.py +++ b/openedx/features/course_experience/tests/views/test_course_updates.py @@ -134,7 +134,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase): # Fetch the view and verify that the query counts haven't changed # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(55, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(54, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_updates_url(self.course) self.client.get(url) From f07f2121baa921b78e24834f99032930480247dc Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 25 Jun 2019 12:50:56 -0400 Subject: [PATCH 5/5] Make has_non_audit_enrollments exclude entitlements --- .../ccx/tests/test_field_override_performance.py | 4 ++-- lms/djangoapps/courseware/tests/test_course_info.py | 4 ++-- lms/djangoapps/courseware/tests/test_views.py | 12 ++++++------ lms/djangoapps/experiments/utils.py | 7 ++++++- .../tests/views/test_course_home.py | 2 +- .../tests/views/test_course_updates.py | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lms/djangoapps/ccx/tests/test_field_override_performance.py b/lms/djangoapps/ccx/tests/test_field_override_performance.py index 8127460f2c..a376c16f4c 100644 --- a/lms/djangoapps/ccx/tests/test_field_override_performance.py +++ b/lms/djangoapps/ccx/tests/test_field_override_performance.py @@ -244,7 +244,7 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase): __test__ = True # TODO: decrease query count as part of REVO-28 - QUERY_COUNT = 34 + QUERY_COUNT = 35 TEST_DATA = { # (providers, course_width, enable_ccx, view_as_ccx): ( # # of sql queries to default, @@ -273,7 +273,7 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase): __test__ = True # TODO: decrease query count as part of REVO-28 - QUERY_COUNT = 34 + QUERY_COUNT = 35 TEST_DATA = { ('no_overrides', 1, True, False): (QUERY_COUNT, 3), diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py index 7b2504be48..d8cb1f19e8 100644 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ b/lms/djangoapps/courseware/tests/test_course_info.py @@ -434,8 +434,8 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest def test_num_queries_instructor_paced(self): # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.instructor_paced_course, 43, 3) + self.fetch_course_info_with_queries(self.instructor_paced_course, 44, 3) def test_num_queries_self_paced(self): # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.self_paced_course, 43, 3) + self.fetch_course_info_with_queries(self.self_paced_course, 44, 3) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 907ec26420..02dc769a5b 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -224,8 +224,8 @@ class IndexQueryTestCase(ModuleStoreTestCase): NUM_PROBLEMS = 20 @ddt.data( - (ModuleStoreEnum.Type.mongo, 10, 180), - (ModuleStoreEnum.Type.split, 4, 174), + (ModuleStoreEnum.Type.mongo, 10, 181), + (ModuleStoreEnum.Type.split, 4, 175), ) @ddt.unpack def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count): @@ -1466,8 +1466,8 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertContains(resp, u"Download Your Certificate") @ddt.data( - (True, 54), - (False, 53) + (True, 55), + (False, 54) ) @ddt.unpack def test_progress_queries_paced_courses(self, self_paced, query_count): @@ -1480,8 +1480,8 @@ class ProgressPageTests(ProgressPageBaseTests): @patch.dict(settings.FEATURES, {'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS': False}) @ddt.data( - (False, 62, 42), - (True, 53, 37) + (False, 63, 43), + (True, 54, 38) ) @ddt.unpack def test_progress_queries(self, enable_waffle, initial, subsequent): diff --git a/lms/djangoapps/experiments/utils.py b/lms/djangoapps/experiments/utils.py index 3ad809affd..cbeb685e86 100644 --- a/lms/djangoapps/experiments/utils.py +++ b/lms/djangoapps/experiments/utils.py @@ -17,6 +17,7 @@ from opaque_keys.edx.keys import CourseKey from course_modes.models import format_course_price, get_cosmetic_verified_display_price, CourseMode from courseware.access import has_staff_access_to_preview_mode from courseware.date_summary import verified_upgrade_deadline_link, verified_upgrade_link_is_valid +from entitlements.models import CourseEntitlement from lms.djangoapps.commerce.utils import EcommerceService from openedx.core.djangoapps.catalog.utils import get_programs from openedx.core.djangoapps.django_comment_common.models import Role @@ -267,6 +268,10 @@ def get_experiment_user_metadata_context(course, user): except CourseEnrollment.DoesNotExist: pass # Not enrolled, use the default values + has_entitlements = False + if user.is_authenticated(): + has_entitlements = CourseEntitlement.objects.filter(user=user).exists() + context = get_base_experiment_metadata_context(course, user, enrollment, user_enrollments) has_staff_access = has_staff_access_to_preview_mode(user, course.id) forum_roles = [] @@ -281,7 +286,7 @@ def get_experiment_user_metadata_context(course, user): user_partitions = {} # TODO: clean up as part of REVO-28 (START) - context['has_non_audit_enrollments'] = has_non_audit_enrollments + context['has_non_audit_enrollments'] = has_non_audit_enrollments or has_entitlements # TODO: clean up as part of REVO-28 (END) context['has_staff_access'] = has_staff_access context['forum_roles'] = forum_roles diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index 6238833d7e..b64d26645a 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -218,7 +218,7 @@ class TestCourseHomePage(CourseHomePageTestCase): # Fetch the view and verify the query counts # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(93, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(94, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/openedx/features/course_experience/tests/views/test_course_updates.py b/openedx/features/course_experience/tests/views/test_course_updates.py index 3f628b2b51..45d51a5448 100644 --- a/openedx/features/course_experience/tests/views/test_course_updates.py +++ b/openedx/features/course_experience/tests/views/test_course_updates.py @@ -134,7 +134,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase): # Fetch the view and verify that the query counts haven't changed # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(54, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(55, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_updates_url(self.course) self.client.get(url)