diff --git a/common/djangoapps/course_modes/helpers.py b/common/djangoapps/course_modes/helpers.py index 0cc13ee57d..e17a03efc9 100644 --- a/common/djangoapps/course_modes/helpers.py +++ b/common/djangoapps/course_modes/helpers.py @@ -63,7 +63,7 @@ def enrollment_mode_display(mode, verification_status, course_id): 'enrollment_value': str(enrollment_value), 'show_image': show_image, 'image_alt': str(image_alt), - 'display_mode': display_mode, + 'display_mode': _enrollment_mode_display(mode, verification_status, course_id) } diff --git a/common/djangoapps/student/views/dashboard.py b/common/djangoapps/student/views/dashboard.py index 176e7965e2..cd3372c9a5 100644 --- a/common/djangoapps/student/views/dashboard.py +++ b/common/djangoapps/student/views/dashboard.py @@ -5,6 +5,7 @@ Dashboard view and supporting methods import datetime import logging +from collections import defaultdict from django.conf import settings from django.contrib import messages @@ -108,7 +109,7 @@ def _get_recently_enrolled_courses(course_enrollments): ] -def _create_recent_enrollment_message(course_enrollments): +def _create_recent_enrollment_message(course_enrollments, course_modes): # lint-amnesty, pylint: disable=unused-argument """ Builds a recent course enrollment message. @@ -117,6 +118,7 @@ def _create_recent_enrollment_message(course_enrollments): Args: course_enrollments (list[CourseEnrollment]): a list of course enrollments. + course_modes (dict): Mapping of course ID's to course mode dictionaries. Returns: A string representing the HTML message output from the message template. @@ -290,6 +292,29 @@ def get_verification_error_reasons_for_display(verification_error_codes): return verification_errors +def reverification_info(statuses): + """ + Returns reverification-related information for *all* of user's enrollments whose + reverification status is in statuses. + + Args: + statuses (list): a list of reverification statuses we want information for + example: ["must_reverify", "denied"] + + Returns: + dictionary of lists: dictionary with one key per status, e.g. + dict["must_reverify"] = [] + dict["must_reverify"] = [some information] + """ + reverifications = defaultdict(list) + + # Sort the data by the reverification_end_date + for status in statuses: + if reverifications[status]: + reverifications[status].sort(key=lambda x: x.date) + return reverifications + + def _credit_statuses(user, course_enrollments): """ Retrieve the status for credit courses. @@ -527,7 +552,9 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem # Check to see if the student has recently enrolled in a course. # If so, display a notification message confirming the enrollment. - enrollment_message = _create_recent_enrollment_message(course_enrollments) + enrollment_message = _create_recent_enrollment_message( + course_enrollments, course_modes_by_course + ) course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True) # Display activation message @@ -552,10 +579,10 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem recovery_email_message = recovery_email_activation_message = None if is_secondary_email_feature_enabled(): try: - PendingSecondaryEmailChange.objects.get(user=user) + pending_email = PendingSecondaryEmailChange.objects.get(user=user) # lint-amnesty, pylint: disable=unused-variable except PendingSecondaryEmailChange.DoesNotExist: try: - AccountRecovery.objects.get(user=user) + account_recovery_obj = AccountRecovery.objects.get(user=user) # lint-amnesty, pylint: disable=unused-variable except AccountRecovery.DoesNotExist: recovery_email_message = Text( _( @@ -604,7 +631,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem ecommerce_service = EcommerceService() inverted_programs = meter.invert_programs() - programs_data = {} + urls, programs_data = {}, {} bundles_on_dashboard_flag = LegacyWaffleFlag(experiments_namespace, 'bundles_on_dashboard', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete @@ -665,6 +692,10 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem verification_status = IDVerificationService.user_status(user) verification_errors = get_verification_error_reasons_for_display(verification_status['error']) + # Gets data for midcourse reverifications, if any are necessary or have failed + statuses = ["approved", "denied", "pending", "must_reverify"] + reverifications = reverification_info(statuses) + enrolled_courses_either_paid = frozenset( enrollment.course_id for enrollment in course_enrollments if enrollment.is_paid_course() @@ -676,6 +707,10 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem if enrollment.is_order_voucher_refundable() ) + # If there are *any* denied reverifications that have not been toggled off, + # we'll display the banner + denied_banner = any(item.display for item in reverifications["denied"]) + # get list of courses having pre-requisites yet to be completed courses_having_prerequisites = frozenset( enrollment.course_id for enrollment in course_enrollments @@ -706,9 +741,11 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem course_enrollments = [ enr for enr in course_enrollments if entitlement.enrollment_course_run.course_id != enr.course_id ] + show_account_activation_popup = request.COOKIES.get(settings.SHOW_ACTIVATE_CTA_POPUP_COOKIE_NAME, None) context = { + 'urls': urls, 'programs_data': programs_data, 'enterprise_message': enterprise_message, 'consent_required_courses': consent_required_courses, @@ -728,11 +765,13 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem 'cert_statuses': cert_statuses, 'credit_statuses': _credit_statuses(user, course_enrollments), 'show_email_settings_for': show_email_settings_for, + 'reverifications': reverifications, 'verification_display': verification_status['should_display'], 'verification_status': verification_status['status'], 'verification_expiry': verification_status['verification_expiry'], 'verification_status_by_course': verify_status_by_course, 'verification_errors': verification_errors, + 'denied_banner': denied_banner, 'billing_email': settings.PAYMENT_SUPPORT_EMAIL, 'show_account_activation_popup': show_account_activation_popup, 'user': user, @@ -740,6 +779,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem 'platform_name': platform_name, 'enrolled_courses_either_paid': enrolled_courses_either_paid, 'enrolled_courses_voucher_refundable': enrolled_courses_voucher_refundable, + 'provider_states': [], 'courses_requirements_not_met': courses_requirements_not_met, 'nav_hidden': True, 'inverted_programs': inverted_programs, diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index b8e2ff99b3..0543f827a0 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -21,6 +21,11 @@ from openedx.core.djangolib.markup import HTML, Text from common.djangoapps.student.models import CourseEnrollment %> +<% + cert_name_short = settings.CERT_NAME_SHORT + cert_name_long = settings.CERT_NAME_LONG +%> + <%block name="pagetitle">${_("Dashboard")} <%block name="bodyclass">view-dashboard is-authenticated @@ -108,6 +113,12 @@ from common.djangoapps.student.models import CourseEnrollment
+ %if banner_account_activation_message: +
+ ${banner_account_activation_message | n, decode.utf8} +
+ %endif + %if enrollment_message:
${enrollment_message | n, decode.utf8} diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index 62d5d3d5e8..14a4ce19fe 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -33,6 +33,9 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG <% reverify_link = IDVerificationService.get_verify_location() + cert_name_short = course_overview.cert_name_short + if cert_name_short == "": + cert_name_short = settings.CERT_NAME_SHORT cert_name_long = course_overview.cert_name_long if cert_name_long == "": @@ -57,6 +60,8 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG verification_status.get('status'), course_overview.id ) + %> + <% mode_class = course_verified_certs.get('display_mode', '') if mode_class: mode_class = ' ' + mode_class ; @@ -304,7 +309,7 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG % endif % else: - <%include file="_dashboard_course_resume.html" args="resume_button_url=resume_button_url, course_overview=course_overview, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, course_target=course_target"/> + <%include file="_dashboard_course_resume.html" args="resume_button_url=resume_button_url, course_overview=course_overview, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, course_target=course_target, related_programs=related_programs"/> % endif % endif
diff --git a/lms/templates/dashboard/_dashboard_course_resume.html b/lms/templates/dashboard/_dashboard_course_resume.html index 5b956c89fa..a4d3c03c2d 100644 --- a/lms/templates/dashboard/_dashboard_course_resume.html +++ b/lms/templates/dashboard/_dashboard_course_resume.html @@ -1,4 +1,4 @@ -<%page args="resume_button_url, course_overview, enrollment, is_unfulfilled_entitlement, course_target" expression_filter="h"/> +<%page args="resume_button_url, course_overview, enrollment, is_unfulfilled_entitlement, course_target, related_programs" expression_filter="h"/> <%! import six diff --git a/themes/edx.org/lms/templates/dashboard.html b/themes/edx.org/lms/templates/dashboard.html index c767946521..1594e4ad4c 100644 --- a/themes/edx.org/lms/templates/dashboard.html +++ b/themes/edx.org/lms/templates/dashboard.html @@ -117,6 +117,12 @@ from common.djangoapps.student.models import CourseEnrollment
+ %if banner_account_activation_message: +
+ ${banner_account_activation_message | n, decode.utf8} +
+ %endif + %if enrollment_message:
${enrollment_message | n, decode.utf8}