From aef4d88eefcab621ce10aa5568e019edcecc74e1 Mon Sep 17 00:00:00 2001 From: julianajlk Date: Fri, 20 May 2022 10:09:03 -0400 Subject: [PATCH] feat: Add logic for happy and non-happy path upgrade msg in learner dashboard (#30368) REV-2466 --- common/djangoapps/student/tests/test_views.py | 46 +++++++++++++++++++ common/djangoapps/student/views/dashboard.py | 15 ++++++ lms/templates/dashboard.html | 2 +- .../dashboard/_dashboard_course_listing.html | 19 ++++++-- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index a874a39fb7..9d88752bf1 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -55,6 +55,12 @@ ONE_WEEK_AGO = now() - timedelta(weeks=1) THREE_YEARS_FROM_NOW = now() + timedelta(days=(365 * 3)) THREE_YEARS_AGO = now() - timedelta(days=(365 * 3)) +# Name of the method to mock for Content Type Gating. +GATING_METHOD_NAME = 'openedx.features.content_type_gating.models.ContentTypeGatingConfig.enabled_for_enrollment' + +# Name of the method to mock for Course Duration Limits. +CDL_METHOD_NAME = 'openedx.features.course_duration_limits.models.CourseDurationLimitConfig.enabled_for_enrollment' + @ddt.ddt @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @@ -953,6 +959,46 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, else: self.assertNotContains(response, html_fragment) + @ddt.data( + # gated_content_on, course_duration_limits_on, upgrade_message + (True, True, 'Upgrade to get full access to the course material'), + (True, False, 'Upgrade to earn'), + (False, True, 'Upgrade to earn'), + (False, False, 'Upgrade to earn'), + ) + @ddt.unpack + def test_happy_path_upgrade_message( + self, + gated_content_on, + course_duration_limits_on, + upgrade_message + ): + """ + Upgrade message should be different for a course depending if it's happy or non-happy path. + Happy path requirements: + - Learner can upgrade (verified_mode) + - FBE is on (has an audit_access_deadline and is able to see gated_content) + """ + with patch.object(EcommerceService, 'is_enabled', return_value=True): + course = CourseFactory.create() + CourseEnrollmentFactory.create( + user=self.user, + course_id=course.id + ) + + CourseModeFactory.create( + course_id=course.id, + mode_slug='verified', + mode_display_name='Verified', + min_price=149, + sku='abcdef', + ) + + with patch(GATING_METHOD_NAME, return_value=gated_content_on): + with patch(CDL_METHOD_NAME, return_value=course_duration_limits_on): + response = self.client.get(reverse('dashboard')) + self.assertContains(response, upgrade_message) + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid for the LMS') @unittest.skipUnless(settings.FEATURES.get("ENABLE_NOTICES"), 'Notices plugin is not enabled') diff --git a/common/djangoapps/student/views/dashboard.py b/common/djangoapps/student/views/dashboard.py index 9ccd0179e7..85305e25ff 100644 --- a/common/djangoapps/student/views/dashboard.py +++ b/common/djangoapps/student/views/dashboard.py @@ -44,6 +44,8 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_ from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled from openedx.core.djangoapps.util.maintenance_banner import add_maintenance_banner from openedx.core.djangolib.markup import HTML, Text +from openedx.features.content_type_gating.models import ContentTypeGatingConfig +from openedx.features.course_duration_limits.access import get_user_course_duration, get_user_course_expiration_date from openedx.features.enterprise_support.api import ( get_dashboard_consent_notification, get_enterprise_learner_portal_context, @@ -762,6 +764,18 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem show_account_activation_popup = request.COOKIES.get(settings.SHOW_ACTIVATE_CTA_POPUP_COOKIE_NAME, None) + fbe_status_list = [] + for enrollment in course_enrollments: + course_key = CourseKey.from_string(str(enrollment.course_id)) + gated_content = ContentTypeGatingConfig.enabled_for_enrollment( + user=request.user, + course_key=course_key + ) + duration = get_user_course_duration(enrollment.user, enrollment.course) + deadline = duration and get_user_course_expiration_date(request.user, enrollment.course) + fbe_is_on = bool(deadline and gated_content) + fbe_status_list.append(fbe_is_on) + context = { 'urls': urls, 'programs_data': programs_data, @@ -808,6 +822,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem 'display_sidebar_account_activation_message': not(user.is_active or hide_dashboard_courses_until_activated), 'display_dashboard_courses': (user.is_active or not hide_dashboard_courses_until_activated), 'empty_dashboard_message': empty_dashboard_message, + 'fbe_status_list': fbe_status_list, 'recovery_email_message': recovery_email_message, 'recovery_email_activation_message': recovery_email_activation_message, 'show_load_all_courses_link': show_load_all_courses_link(user, course_limit, course_enrollments), diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index c7fa05bde9..2bebd24dc3 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -224,7 +224,7 @@ from common.djangoapps.student.models import CourseEnrollment show_consent_link = (session_id in consent_required_courses) resume_button_url = resume_button_urls[dashboard_index] %> - <%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, entitlement_expiration_date=entitlement_expiration_date, entitlement_expired_at=entitlement_expired_at, show_courseware_link=show_courseware_link, cert_status=cert_status, can_refund_entitlement=can_refund_entitlement, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_voucher_refundable=is_course_voucher_refundable, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name, resume_button_url=resume_button_url, partner_managed_enrollment=partner_managed_enrollment' /> + <%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, fbe_status_list=fbe_status_list, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, entitlement_expiration_date=entitlement_expiration_date, entitlement_expired_at=entitlement_expired_at, show_courseware_link=show_courseware_link, cert_status=cert_status, can_refund_entitlement=can_refund_entitlement, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_voucher_refundable=is_course_voucher_refundable, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name, resume_button_url=resume_button_url, partner_managed_enrollment=partner_managed_enrollment' /> % endfor % if show_load_all_courses_link:
diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index b58479ef81..316bb88f49 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -1,4 +1,4 @@ -<%page args="course_overview, enrollment, entitlement, entitlement_session, course_card_index, is_unfulfilled_entitlement, is_fulfilled_entitlement, entitlement_available_sessions, entitlement_expiration_date, entitlement_expired_at, show_courseware_link, cert_status, can_refund_entitlement, can_unenroll, credit_status, show_email_settings, course_mode_info, is_paid_course, is_course_voucher_refundable, course_requirements, dashboard_index, share_settings, related_programs, display_course_modes_on_dashboard, show_consent_link, enterprise_customer_name, resume_button_url, partner_managed_enrollment" expression_filter="h"/> +<%page args="course_overview, enrollment, entitlement, entitlement_session, course_card_index, fbe_status_list, is_unfulfilled_entitlement, is_fulfilled_entitlement, entitlement_available_sessions, entitlement_expiration_date, entitlement_expired_at, show_courseware_link, cert_status, can_refund_entitlement, can_unenroll, credit_status, show_email_settings, course_mode_info, is_paid_course, is_course_voucher_refundable, course_requirements, dashboard_index, share_settings, related_programs, display_course_modes_on_dashboard, show_consent_link, enterprise_customer_name, resume_button_url, partner_managed_enrollment" expression_filter="h"/> <%! import datetime @@ -48,6 +48,8 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG and not entitlement and course_mode_info['verified_sku'] ) + for fbe_is_on in fbe_status_list: + fbe_is_on = fbe_is_on %> <% @@ -382,6 +384,7 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG
+ % if fbe_is_on: ${Text(_("{start_bold}Get the most out of your course!{end_bold} Upgrade to get full access to the course material, unlock both graded and non-graded assignments, and earn a {link_start}verified certificate{link_end} to showcase on your resumé.")).format( start_bold=HTML(''), end_bold=HTML(''), @@ -389,9 +392,19 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG marketing_link('WHAT_IS_VERIFIED_CERT'), enrollment.course_id ), - link_end=HTML(''), - cert_name_long=cert_name_long + link_end=HTML('') )} + % else: + ${Text(_("{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a {link_start}verified certificate{link_end} to showcase on your resumé.")).format( + start_bold=HTML(''), + end_bold=HTML(''), + link_start=HTML('').format( + marketing_link('WHAT_IS_VERIFIED_CERT'), + enrollment.course_id + ), + link_end=HTML('') + )} + % endif