From cbb4cfb988daac19190e48365bbfd05b307ec29b Mon Sep 17 00:00:00 2001 From: Diane Kaplan Date: Fri, 8 May 2020 10:35:10 -0400 Subject: [PATCH] Add financial assistance link in course tools (#23921) Add financial assistance link in course tools for eligible courses, so it'll be more visible to learners --- lms/djangoapps/courseware/course_tools.py | 63 ++++++++++++++++- .../courseware/tests/test_course_info.py | 4 +- .../courseware/tests/test_course_tools.py | 67 +++++++++++++++++++ lms/envs/bok_choy.py | 3 + .../tests/views/test_course_home.py | 2 +- setup.py | 1 + 6 files changed, 136 insertions(+), 4 deletions(-) diff --git a/lms/djangoapps/courseware/course_tools.py b/lms/djangoapps/courseware/course_tools.py index b13116cd61..5caf682c3e 100644 --- a/lms/djangoapps/courseware/course_tools.py +++ b/lms/djangoapps/courseware/course_tools.py @@ -8,11 +8,12 @@ import datetime import pytz from crum import get_current_request from django.utils.translation import ugettext as _ - +from django.urls import reverse from course_modes.models import CourseMode from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link from openedx.features.course_experience.course_tools import CourseTool from student.models import CourseEnrollment +from openedx.core.djangoapps.content.course_overviews.models import CourseOverview class VerifiedUpgradeTool(CourseTool): @@ -73,3 +74,63 @@ class VerifiedUpgradeTool(CourseTool): """ request = get_current_request() return verified_upgrade_deadline_link(request.user, course_id=course_key) + + +class FinancialAssistanceTool(CourseTool): + """ + The financial assistance tool. + """ + @classmethod + def analytics_id(cls): + """ + Returns an id to uniquely identify this tool in analytics events. + """ + return 'edx.tool.financial_assistance' + + @classmethod + def is_enabled(cls, request, course_key): + """ + Show this link for active courses where financial assistance is available, unless upgrade deadline has passed + """ + now = datetime.datetime.now(pytz.UTC) + try: + course_overview = CourseOverview.objects.get(id=course_key) + except CourseOverview.DoesNotExist: + course_overview = None + + # hide the link for archived courses + if course_overview is not None and course_overview.end_date is not None and now > course_overview.end_date: + return False + + # hide the link if not logged in or user not enrolled in the course + if not request.user or not CourseEnrollment.is_enrolled(request.user, course_key): + return False + + # hide if there's a course_upgrade_enrollment in the past + enrollment = CourseEnrollment.get_enrollment(request.user, course_key) + if enrollment.course_upgrade_deadline: + if now > enrollment.course_upgrade_deadline: + return False + + return bool(course_overview.eligible_for_financial_aid) + + @classmethod + def title(cls, course_key=None): + """ + Returns the title of this tool. + """ + return _('Financial Assistance') + + @classmethod + def icon_classes(cls, course_key=None): + """ + Returns the icon classes needed to represent this tool. + """ + return 'fa fa-info' + + @classmethod + def url(cls, course_key): + """ + Returns the URL for this tool for the specified course key. + """ + return reverse('financial_assistance') diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py index 578cd8b7dc..59b535330e 100644 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ b/lms/djangoapps/courseware/tests/test_course_info.py @@ -431,8 +431,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_course_tools.py b/lms/djangoapps/courseware/tests/test_course_tools.py index 05115b68ba..a04ca01594 100644 --- a/lms/djangoapps/courseware/tests/test_course_tools.py +++ b/lms/djangoapps/courseware/tests/test_course_tools.py @@ -12,6 +12,7 @@ from mock import patch from course_modes.models import CourseMode from course_modes.tests.factories import CourseModeFactory +from lms.djangoapps.courseware.course_tools import FinancialAssistanceTool from lms.djangoapps.courseware.course_tools import VerifiedUpgradeTool from lms.djangoapps.courseware.models import DynamicUpgradeDeadlineConfiguration from openedx.core.djangoapps.content.course_overviews.models import CourseOverview @@ -103,3 +104,69 @@ class VerifiedUpgradeToolTest(SharedModuleStoreTestCase): self.course_verified_mode.expiration_datetime = None self.course_verified_mode.save() self.assertFalse(VerifiedUpgradeTool().is_enabled(self.request, self.course.id)) + + +class FinancialAssistanceToolTest(SharedModuleStoreTestCase): + """ + Tests for FinancialAssistanceTool + """ + @classmethod + def setUpClass(cls): + super(FinancialAssistanceToolTest, cls).setUpClass() + cls.now = datetime.datetime.now(pytz.UTC) + + cls.course = CourseFactory.create( + org='edX', + number='test', + display_name='Test Course', + self_paced=True, + ) + cls.course_overview = CourseOverview.get_from_id(cls.course.id) + + @override_waffle_flag(CREATE_SCHEDULE_WAFFLE_FLAG, True) + def setUp(self): + super(FinancialAssistanceToolTest, self).setUp() + + self.course_financial_mode = CourseModeFactory( + course_id=self.course.id, + mode_slug=CourseMode.VERIFIED, + expiration_datetime=self.now + datetime.timedelta(days=1), + ) + DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True) + + self.request = RequestFactory().request() + crum.set_current_request(self.request) + self.addCleanup(crum.set_current_request, None) + self.enrollment = CourseEnrollmentFactory( + course_id=self.course.id, + mode=CourseMode.AUDIT, + course=self.course_overview, + ) + self.request.user = self.enrollment.user + self.enrollment.course_upgrade_deadline = self.now - datetime.timedelta(days=1) + self.enrollment.save() + + def test_tool_visible_logged_in(self): + self.course_financial_mode.save() + self.assertTrue(FinancialAssistanceTool().is_enabled(self.request, self.course.id)) + + def test_tool_not_visible_when_not_eligible(self): + self.course_overview.eligible_for_financial_aid = False + self.course_overview.save() + self.assertFalse(FinancialAssistanceTool().is_enabled(self.request, self.course_overview.id)) + + def test_tool_not_visible_when_user_not_unrolled(self): + self.course_financial_mode.save() + self.request.user = None + self.assertFalse(FinancialAssistanceTool().is_enabled(self.request, self.course.id)) + + # mock the response from get_enrollment to use enrollment with course_upgrade_deadline in the past + @patch('lms.djangoapps.courseware.course_tools.CourseEnrollment.get_enrollment') + def test_not_visible_when_upgrade_deadline_has_passed(self, get_enrollment_mock): + get_enrollment_mock.return_value = self.enrollment + self.assertFalse(FinancialAssistanceTool().is_enabled(self.request, self.course.id)) + + def test_tool_not_visible_when_end_date_passed(self): + self.course_overview.end_date = self.now - datetime.timedelta(days=30) + self.course_overview.save() + self.assertFalse(FinancialAssistanceTool().is_enabled(self.request, self.course_overview.id)) diff --git a/lms/envs/bok_choy.py b/lms/envs/bok_choy.py index 513dbf4928..cc3e6421f2 100644 --- a/lms/envs/bok_choy.py +++ b/lms/envs/bok_choy.py @@ -61,6 +61,9 @@ update_module_store_settings( PLATFORM_NAME = ugettext_lazy(u"édX") PLATFORM_DESCRIPTION = ugettext_lazy(u"Open édX Platform") +################################ FEATURE FLAGS ################################ +FEATURES['ENABLE_FINANCIAL_ASSISTANCE_FORM'] = True + ############################ STATIC FILES ############################# # Serve static files at /static directly from the staticfiles directory under test root 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 6e56952bd1..70b256f03b 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -219,7 +219,7 @@ class TestCourseHomePage(CourseHomePageTestCase): # Fetch the view and verify the query counts # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(74, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(75, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/setup.py b/setup.py index cc5df8db8c..257131cb2e 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ setup( "course_updates = openedx.features.course_experience.plugins:CourseUpdatesTool", "course_reviews = openedx.features.course_experience.plugins:CourseReviewsTool", "verified_upgrade = lms.djangoapps.courseware.course_tools:VerifiedUpgradeTool", + "financial_assistance = lms.djangoapps.courseware.course_tools:FinancialAssistanceTool", ], "openedx.user_partition_scheme": [ "random = openedx.core.djangoapps.user_api.partition_schemes:RandomUserPartitionScheme",