fix: Handle missing user profile when setting a name in a course certificate (#28319)

MICROBA-1410
This commit is contained in:
Christie Rice
2021-08-02 10:58:13 -04:00
committed by GitHub
parent 9cda17bf8d
commit 5fa4fcea5e
4 changed files with 75 additions and 5 deletions

View File

@@ -52,7 +52,7 @@ def get_course_enrollment(user, course_run_key):
def get_phone_number(user_id):
"""
Get a users phone number from the profile, if
Get a user's phone number from the profile, if
one exists. Otherwise, return None.
"""
try:
@@ -63,6 +63,18 @@ def get_phone_number(user_id):
return student.phone_number or None
def get_name(user_id):
"""
Get a user's name from their profile, if one exists. Otherwise, return None.
"""
try:
student = _UserProfile.objects.get(user_id=user_id)
except _UserProfile.DoesNotExist:
log.exception(f'Could not find UserProfile for id {user_id}')
return None
return student.name or None
def get_course_access_role(user, org, course_id, role):
"""
Get a specific CourseAccessRole object. Return None if

View File

@@ -26,8 +26,10 @@ from common.djangoapps.student.models import (
ManualEnrollmentAudit,
PendingEmailChange,
PendingNameChange,
UserCelebration
UserCelebration,
UserProfile
)
from common.djangoapps.student.models_api import get_name
from common.djangoapps.student.tests.factories import AccountRecoveryFactory, CourseEnrollmentFactory, UserFactory
from lms.djangoapps.courseware.models import DynamicUpgradeDeadlineConfiguration
from lms.djangoapps.courseware.toggles import (
@@ -728,3 +730,30 @@ class TestUserPostSaveCallback(SharedModuleStoreTestCase):
course_enrollment.save()
return user
class TestProfile(SharedModuleStoreTestCase):
"""
Tests for the user profile
"""
def setUp(self):
super().setUp()
self.user = UserFactory.create()
self.profile = UserProfile.objects.get(user_id=self.user.id)
self.name = self.profile.name
self.course = CourseFactory.create()
def test_name(self):
"""
Test retrieval of the name
"""
assert self.name
name = get_name(self.user.id)
assert name == self.name
def test_name_missing_profile(self):
"""
Test retrieval of the name when the user profile doesn't exist
"""
name = get_name(None)
assert not name

View File

@@ -10,7 +10,7 @@ These methods should be called from tasks.
import logging
from uuid import uuid4
from common.djangoapps.student.models import UserProfile
from common.djangoapps.student import models_api as student_api
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.models import GeneratedCertificate
from lms.djangoapps.certificates.utils import emit_certificate_event
@@ -66,8 +66,9 @@ def _generate_certificate(user, course_key, status, enrollment_mode, course_grad
# Retrieve the existing certificate for the learner if it exists
existing_certificate = GeneratedCertificate.certificate_for_student(user, course_key)
profile = UserProfile.objects.get(user=user)
profile_name = profile.name
profile_name = student_api.get_name(user.id)
if not profile_name:
profile_name = ''
# Retain the `verify_uuid` from an existing certificate if possible, this will make it possible for the learner to
# keep the existing URL to their certificate

View File

@@ -2,8 +2,10 @@
Tests for certificate generation
"""
import logging
from unittest import mock
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import UserProfile
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.util.testing import EventTestMixin
from lms.djangoapps.certificates.data import CertificateStatuses
@@ -15,6 +17,8 @@ from xmodule.modulestore.tests.factories import CourseFactory
log = logging.getLogger(__name__)
PROFILE_NAME_METHOD = 'common.djangoapps.student.models_api.get_name'
class CertificateTests(EventTestMixin, ModuleStoreTestCase):
"""
@@ -26,6 +30,8 @@ class CertificateTests(EventTestMixin, ModuleStoreTestCase):
# Create user, a course run, and an enrollment
self.u = UserFactory()
self.profile = UserProfile.objects.get(user_id=self.u.id)
self.name = self.profile.name
self.cr = CourseFactory()
self.key = self.cr.id # pylint: disable=no-member
CourseEnrollmentFactory(
@@ -65,6 +71,7 @@ class CertificateTests(EventTestMixin, ModuleStoreTestCase):
assert cert.status == CertificateStatuses.downloadable
assert cert.mode == self.enrollment_mode
assert cert.grade == self.grade
assert cert.name == self.name
def test_generation_existing_unverified(self):
"""
@@ -159,3 +166,24 @@ class CertificateTests(EventTestMixin, ModuleStoreTestCase):
self.enrollment_mode, self.grade, self.gen_mode)
assert generated_cert.status, CertificateStatuses.downloadable
assert generated_cert.verify_uuid != ''
def test_generation_missing_profile(self):
"""
Test certificate generation when the user profile is missing
"""
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.AUDIT,
status=CertificateStatuses.unverified
)
with mock.patch(PROFILE_NAME_METHOD, return_value=None):
generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable, self.enrollment_mode,
self.grade, self.gen_mode)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.status == CertificateStatuses.downloadable
assert cert.mode == self.enrollment_mode
assert cert.grade == self.grade
assert cert.name == ''