diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py index 49a58f6083..bb85795a16 100644 --- a/common/djangoapps/student/helpers.py +++ b/common/djangoapps/student/helpers.py @@ -770,3 +770,16 @@ def does_user_profile_exist(user): return hasattr(user, 'profile') except (ProgrammingError, ObjectDoesNotExist): return False + + +def user_has_passing_grade_in_course(user, enrollment): + """ + Check to see if a user has passing grade for a course + """ + try: + course_grade = CourseGradeFactory().read(user, course=enrollment.course_overview, create_if_needed=False) + if course_grade: + return course_grade.passed + except AttributeError: + pass + return False diff --git a/common/djangoapps/student/views/dashboard.py b/common/djangoapps/student/views/dashboard.py index cd3372c9a5..0613feb43d 100644 --- a/common/djangoapps/student/views/dashboard.py +++ b/common/djangoapps/student/views/dashboard.py @@ -47,7 +47,12 @@ from openedx.features.enterprise_support.api import ( get_enterprise_learner_portal_context, ) from common.djangoapps.student.api import COURSE_DASHBOARD_PLUGIN_VIEW_NAME -from common.djangoapps.student.helpers import cert_info, check_verify_status_by_course, get_resume_urls_for_enrollments +from common.djangoapps.student.helpers import ( + cert_info, + check_verify_status_by_course, + get_resume_urls_for_enrollments, + user_has_passing_grade_in_course +) from common.djangoapps.student.models import ( AccountRecovery, CourseEnrollment, @@ -675,10 +680,11 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem # If a course is not included in this dictionary, # there is no verification messaging to display. verify_status_by_course = check_verify_status_by_course(user, course_enrollments) - cert_statuses = { - enrollment.course_id: cert_info(request.user, enrollment) - for enrollment in course_enrollments - } + cert_statuses = {} + passing_courses = {} + for enrollment in course_enrollments: + cert_statuses[enrollment.course_id] = cert_info(request.user, enrollment) + passing_courses[enrollment.course_id] = user_has_passing_grade_in_course(user, enrollment) # only show email settings for Mongo course and when bulk email is turned on show_email_settings_for = frozenset( @@ -763,6 +769,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem 'show_courseware_links_for': show_courseware_links_for, 'all_course_modes': course_mode_info, 'cert_statuses': cert_statuses, + 'passing_courses': passing_courses, 'credit_statuses': _credit_statuses(user, course_enrollments), 'show_email_settings_for': show_email_settings_for, 'reverifications': reverifications, diff --git a/lms/djangoapps/course_home_api/outline/v1/views.py b/lms/djangoapps/course_home_api/outline/v1/views.py index f842275a37..9706df39fb 100644 --- a/lms/djangoapps/course_home_api/outline/v1/views.py +++ b/lms/djangoapps/course_home_api/outline/v1/views.py @@ -340,6 +340,12 @@ class OutlineTabView(RetrieveAPIView): if user_grade: user_has_passing_grade = user_grade.passed + user_has_passing_grade = False + if not request.user.is_anonymous: + user_grade = CourseGradeFactory().read(request.user, course) + if user_grade: + user_has_passing_grade = user_grade.passed + data = { 'access_expiration': access_expiration, 'cert_data': cert_data, diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 0543f827a0..477e160aa9 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -207,6 +207,7 @@ from common.djangoapps.student.models import CourseEnrollment session_id = enrollment.course_id show_courseware_link = show_courseware_links_for.get(session_id, False) cert_status = cert_statuses.get(session_id) + is_passing_course = passing_courses.get(session_id) or False can_refund_entitlement = entitlement and entitlement.is_entitlement_refundable() partner_managed_enrollment = enrollment.mode == 'masters' can_unenroll = False if partner_managed_enrollment else (not cert_status) or cert_status.get('can_unenroll') if not unfulfilled_entitlement else False @@ -220,7 +221,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, verification_status=course_verification_status, 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, 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, is_passing_course=is_passing_course, 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, verification_status=course_verification_status, 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_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html index c0ded0d125..1dcf5da5b5 100644 --- a/lms/templates/dashboard/_dashboard_certificate_information.html +++ b/lms/templates/dashboard/_dashboard_certificate_information.html @@ -1,4 +1,4 @@ -<%page expression_filter="h" args="cert_status, course_overview, enrollment, reverify_link" /> +<%page expression_filter="h" args="cert_status, course_ended_not_passing, course_overview, enrollment, reverify_link" /> <%! from django.urls import reverse @@ -33,7 +33,10 @@ elif cert_status['status'] == CertificateStatuses.notpassing: else: status_css_class = 'course-status-processing' %> -<% requesting_post_url = reverse('generate_user_cert', args=[str(course_overview.id)]) %> +<% + requesting_post_url = reverse('generate_user_cert', args=[str(course_overview.id)]) + progress_page_url = reverse('progress', args=[str(course_overview.id)]) +%> % if cert_status['status'] != 'processing': % if cert_status['status'] == 'certificate_earned_but_not_available': @@ -161,5 +164,21 @@ else: % endif +% elif course_ended_not_passing: +
+
+ <% + container_string = _("You are not eligible for a certificate.") + %> + +
+ +
% endif diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index ea52213f4a..9534683d59 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, verification_status, 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, is_unfulfilled_entitlement, is_fulfilled_entitlement, entitlement_available_sessions, entitlement_expiration_date, entitlement_expired_at, show_courseware_link, cert_status, is_passing_course, can_refund_entitlement, can_unenroll, credit_status, show_email_settings, course_mode_info, is_paid_course, is_course_voucher_refundable, verification_status, 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 @@ -43,6 +43,11 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG is_course_expired = hasattr(show_courseware_link, 'error_code') and show_courseware_link.error_code == 'audit_expired' %> +<% + is_audit_enrollment = enrollment.mode == "audit" or enrollment.mode == "honor" + course_ended_not_passing = course_overview.has_ended() and is_passing_course == False and is_audit_enrollment == False +%> + <%namespace name='static' file='../static_content.html'/>
  • @@ -350,7 +355,7 @@ from lms.djangoapps.experiments.utils import UPSELL_TRACKING_FLAG % endif % if cert_status: - <%include file='_dashboard_certificate_information.html' args='cert_status=cert_status,course_overview=course_overview, enrollment=enrollment, reverify_link=reverify_link'/> + <%include file='_dashboard_certificate_information.html' args='cert_status=cert_status, course_ended_not_passing=course_ended_not_passing, course_overview=course_overview, enrollment=enrollment, reverify_link=reverify_link'/> % endif % if credit_status is not None: diff --git a/themes/edx.org/lms/templates/dashboard.html b/themes/edx.org/lms/templates/dashboard.html index 1594e4ad4c..06fe445696 100644 --- a/themes/edx.org/lms/templates/dashboard.html +++ b/themes/edx.org/lms/templates/dashboard.html @@ -237,6 +237,7 @@ from common.djangoapps.student.models import CourseEnrollment session_id = enrollment.course_id show_courseware_link = show_courseware_links_for.get(session_id, False) cert_status = cert_statuses.get(session_id) + is_passing_course = passing_courses.get(session_id) or False can_refund_entitlement = entitlement and entitlement.is_entitlement_refundable() partner_managed_enrollment = enrollment.mode == 'masters' can_unenroll = False if partner_managed_enrollment else (not cert_status) or cert_status.get('can_unenroll') if not unfulfilled_entitlement else False @@ -251,7 +252,7 @@ from common.djangoapps.student.models import CourseEnrollment course_overview = enrollment.course_overview 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, verification_status=course_verification_status, 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, 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, is_passing_course=is_passing_course, 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, verification_status=course_verification_status, 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: