fix: handle exception getting cert statuses (#31490)
If a user has a certificate in a deleted course, an issue with how the course is loaded from the cache can cause an exception that breaks our code. This adds a wrapper to fail gracefully and log the exception for future tracking / investigation.
This commit is contained in:
@@ -649,6 +649,42 @@ class TestDashboardView(BaseTestDashboardView):
|
||||
},
|
||||
)
|
||||
|
||||
@patch.dict(settings.FEATURES, ENTERPRISE_ENABLED=False)
|
||||
@patch("lms.djangoapps.learner_home.views.cert_info")
|
||||
def test_get_cert_statuses_exception(self, mock_get_cert_info):
|
||||
"""Test that cert information gets loaded correctly"""
|
||||
|
||||
# Given I am logged in
|
||||
self.log_in()
|
||||
|
||||
# (and we have tons of mocks to avoid integration tests)
|
||||
mock_enrollment = create_test_enrollment(
|
||||
self.user, course_mode=CourseMode.VERIFIED
|
||||
)
|
||||
|
||||
# but have an issue with a particular certificate
|
||||
mock_get_cert_info.side_effect = Exception("test exception")
|
||||
|
||||
# When I request the dashboard
|
||||
response = self.client.get(self.view_url)
|
||||
|
||||
# Then I get the expected success response
|
||||
assert response.status_code == 200
|
||||
response_data = json.loads(response.content)
|
||||
|
||||
empty_cert_data = {
|
||||
"availableDate": None,
|
||||
"isRestricted": False,
|
||||
"isEarned": False,
|
||||
"isDownloadable": False,
|
||||
"certPreviewUrl": None,
|
||||
}
|
||||
|
||||
# with empty cert data instead of a break
|
||||
self.assertDictEqual(
|
||||
response_data["courses"][0]["certificate"], empty_cert_data
|
||||
)
|
||||
|
||||
@patch.dict(settings.FEATURES, ENTERPRISE_ENABLED=False)
|
||||
@patch("openedx.core.djangoapps.programs.utils.get_programs")
|
||||
def test_get_for_one_of_course_programs(self, mock_get_programs):
|
||||
|
||||
@@ -238,10 +238,24 @@ def get_ecommerce_payment_page(user):
|
||||
@function_trace("get_cert_statuses")
|
||||
def get_cert_statuses(user, course_enrollments):
|
||||
"""Get cert status by course for user enrollments"""
|
||||
return {
|
||||
enrollment.course_id: cert_info(user, enrollment)
|
||||
for enrollment in course_enrollments
|
||||
}
|
||||
|
||||
cert_statuses = {}
|
||||
|
||||
for enrollment in course_enrollments:
|
||||
# APER-2171 - trying to get a cert for a deleted course can throw an exception
|
||||
# Wrap in exception handling to avoid this issue.
|
||||
try:
|
||||
certificate_for_course = cert_info(user, enrollment)
|
||||
|
||||
if certificate_for_course:
|
||||
cert_statuses[enrollment.course_id] = certificate_for_course
|
||||
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
logger.exception(
|
||||
f"Error getting certificate status for (user, course) ({user}, {enrollment.course_id}): {ex}"
|
||||
)
|
||||
|
||||
return cert_statuses
|
||||
|
||||
|
||||
@function_trace("get_org_block_and_allow_lists")
|
||||
|
||||
Reference in New Issue
Block a user