From 07837cf54e5c6734a6021b66a12e16eededeb37b Mon Sep 17 00:00:00 2001 From: Justin Hynes Date: Tue, 2 Mar 2021 08:38:06 -0500 Subject: [PATCH] MICROBA-1024 | Move the allowlist and blocklist checks to certificates app [MICROBA-1024] - Move some of the recently added logic from the instructor app to the certificates app - Attempt to not use other certificate models directly in the code I am touching, moving this logic to certificates as well. --- lms/djangoapps/certificates/api.py | 80 ++++++++-- lms/djangoapps/certificates/tests/test_api.py | 125 +++++++++++++++- lms/djangoapps/courseware/views/views.py | 2 +- lms/djangoapps/instructor/tests/test_api.py | 93 ------------ lms/djangoapps/instructor/views/api.py | 140 +++++++----------- 5 files changed, 239 insertions(+), 201 deletions(-) diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index c16eb68602..5a97ecd22b 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -125,14 +125,16 @@ def get_certificates_for_user(username): return certs -def get_certificate_for_user(username, course_key): +def get_certificate_for_user(username, course_key, format_results=True): """ Retrieve certificate information for a particular user for a specific course. Arguments: username (unicode): The identifier of the user. course_key (CourseKey): A Course Key. - Returns: dict + Returns: + A dict containing information about the certificate or, optionally, + the GeneratedCertificate object itself. """ try: cert = GeneratedCertificate.eligible_certificates.get( @@ -141,7 +143,11 @@ def get_certificate_for_user(username, course_key): ) except GeneratedCertificate.DoesNotExist: return None - return format_certificate_for_user(username, cert) + + if format_results: + return format_certificate_for_user(username, cert) + else: + return cert def get_certificates_for_user_by_course_keys(user, course_keys): @@ -283,24 +289,21 @@ def set_cert_generation_enabled(course_key, is_enabled): log.info("Disabled self-generated certificates for course '%s'.", str(course_key)) -def is_certificate_invalid(student, course_key): - """Check that whether the student in the course has been invalidated - for receiving certificates. +def is_certificate_invalidated(student, course_key): + """Check whether the certificate belonging to the given student (in given course) has been invalidated. Arguments: student (user object): logged-in user course_key (CourseKey): The course identifier. Returns: - Boolean denoting whether the student in the course is invalidated - to receive certificates + Boolean denoting whether the certificate has been invalidated for this learner. """ - is_invalid = False certificate = GeneratedCertificate.certificate_for_student(student, course_key) - if certificate is not None: - is_invalid = CertificateInvalidation.has_certificate_invalidation(student, course_key) + if certificate: + return CertificateInvalidation.has_certificate_invalidation(student, course_key) - return is_invalid + return False def cert_generation_enabled(course_key): @@ -569,3 +572,56 @@ def get_allowlisted_users(course_key): return User.objects.none() return User.objects.filter(certificatewhitelist__course_id=course_key, certificatewhitelist__whitelist=True) + + +def create_certificate_allowlist_entry(user, course_key, notes): + """ + Creates a certificate exception for a given learner in a given course-run. + """ + certificate_allowlist, __ = CertificateWhitelist.objects.get_or_create( + user=user, + course_id=course_key, + defaults={ + 'whitelist': True, + 'notes': notes, + } + ) + + return certificate_allowlist + + +def create_certificate_invalidation_entry(certificate, user_requesting_invalidation, notes): + """ + Invalidates a certificate with the given certificate id. + """ + certificate_invalidation, __ = CertificateInvalidation.objects.update_or_create( + generated_certificate=certificate, + defaults={ + 'active': True, + 'invalidated_by': user_requesting_invalidation, + 'notes': notes, + } + ) + + return certificate_invalidation + + +def get_allowlist_entry(user, course_key): + """ + Retrieves and returns an allowlist entry for a given learner and course-run. + """ + return CertificateWhitelist.objects.get(user=user, course_id=course_key) + + +def get_certificate_invalidation_entry(certificate): + """ + Retrieves and returns an certificate invalidation entry for a given certificate id. + """ + return CertificateInvalidation.objects.get(generated_certificate=certificate) + + +def is_on_allowlist(user, course_key): + """ + Determines if a learner appears on the allowlist for a given course-run. + """ + return CertificateWhitelist.objects.filter(user=user, course_id=course_key, whitelist=True).exists() diff --git a/lms/djangoapps/certificates/tests/test_api.py b/lms/djangoapps/certificates/tests/test_api.py index c0c02c6542..693de69a7f 100644 --- a/lms/djangoapps/certificates/tests/test_api.py +++ b/lms/djangoapps/certificates/tests/test_api.py @@ -33,17 +33,22 @@ from common.djangoapps.util.testing import EventTestMixin from lms.djangoapps.certificates.api import ( cert_generation_enabled, certificate_downloadable_status, + create_certificate_allowlist_entry, + create_certificate_invalidation_entry, example_certificates_status, generate_example_certificates, generate_user_certificates, + get_allowlist_entry, get_allowlisted_users, get_certificate_for_user, get_certificates_for_user, get_certificates_for_user_by_course_keys, get_certificate_footer_context, get_certificate_header_context, + get_certificate_invalidation_entry, get_certificate_url, - is_certificate_invalid, + is_certificate_invalidated, + is_on_allowlist, set_cert_generation_enabled ) from lms.djangoapps.certificates.generation_handler import CERTIFICATES_USE_ALLOWLIST @@ -260,7 +265,7 @@ class CertificateIsInvalid(WebCertificateTestMixin, ModuleStoreTestCase): ) # Also check query count for 'is_certificate_invalid' method. with self.assertNumQueries(1): - assert not is_certificate_invalid(self.student, course.id) + assert not is_certificate_invalidated(self.student, course.id) @ddt.data( CertificateStatuses.generating, @@ -276,7 +281,7 @@ class CertificateIsInvalid(WebCertificateTestMixin, ModuleStoreTestCase): True. """ generated_cert = self._generate_cert(status) self._invalidate_certificate(generated_cert, True) - assert is_certificate_invalid(self.student, self.course.id) + assert is_certificate_invalidated(self.student, self.course.id) @ddt.data( CertificateStatuses.generating, @@ -292,7 +297,7 @@ class CertificateIsInvalid(WebCertificateTestMixin, ModuleStoreTestCase): false than method will return false. """ generated_cert = self._generate_cert(status) self._invalidate_certificate(generated_cert, False) - assert not is_certificate_invalid(self.student, self.course.id) + assert not is_certificate_invalidated(self.student, self.course.id) @ddt.data( CertificateStatuses.generating, @@ -315,7 +320,7 @@ class CertificateIsInvalid(WebCertificateTestMixin, ModuleStoreTestCase): ) # Also check query count for 'is_certificate_invalid' method. with self.assertNumQueries(2): - assert is_certificate_invalid(self.student, self.course.id) + assert is_certificate_invalidated(self.student, self.course.id) def _invalidate_certificate(self, certificate, active): """ Dry method to mark certificate as invalid. """ @@ -876,3 +881,113 @@ class AllowlistTests(ModuleStoreTestCase): users = get_allowlisted_users(self.third_course_run_key) assert 0 == users.count() + + +class InstructorDashboardFunctionalityTests(ModuleStoreTestCase): + """ + Tests for some functionality that the Instructor Dashboard django app relies on. + """ + + def setUp(self): + super().setUp() + + self.global_staff = GlobalStaffFactory() + self.user = UserFactory() + self.course_run = CourseFactory() + self.course_run_key = self.course_run.id # pylint: disable=no-member + + CourseEnrollmentFactory( + user=self.user, + course_id=self.course_run_key, + is_active=True, + mode="verified", + ) + + def test_create_certificate_invalidation_entry(self): + """ + Test to verify that we can use the functionality defined in the Certificates api.py to create certificate + invalidation entries. This is functionality the Instructor Dashboard django app relies on. + """ + certificate = GeneratedCertificateFactory.create( + user=self.user, + course_id=self.course_run_key, + status=CertificateStatuses.unavailable, + mode='verified' + ) + + result = create_certificate_invalidation_entry(certificate, self.global_staff, "Test!") + + assert result.generated_certificate == certificate + assert result.active is True + assert result.notes == "Test!" + + def test_create_certificate_allowlist_entry(self): + """ + Test to verify that we can use the functionality defined in the Certificates api.py to create allowlist + entries. This is functionality the Instructor Dashboard django app relies on. + """ + result = create_certificate_allowlist_entry(self.user, self.course_run_key, "Testing!") + + assert result.course_id == self.course_run_key + assert result.user == self.user + assert result.notes == "Testing!" + + def test_get_allowlist_entry(self): + """ + Test to verify that we can retrieve an allowlist entry for a learner. + """ + allowlist_entry = CertificateWhitelistFactory.create(course_id=self.course_run_key, user=self.user) + + retrieved_entry = get_allowlist_entry(self.user, self.course_run_key) + + assert retrieved_entry.id == allowlist_entry.id + assert retrieved_entry.course_id == allowlist_entry.course_id + assert retrieved_entry.user == allowlist_entry.user + + def test_get_certificate_invalidation_entry(self): + """ + Test to verify that we can retrieve a certificate invalidation entry for a learner. + """ + certificate = GeneratedCertificateFactory.create( + user=self.user, + course_id=self.course_run_key, + status=CertificateStatuses.unavailable, + mode='verified' + ) + + invalidation = CertificateInvalidationFactory.create( + generated_certificate=certificate, + invalidated_by=self.global_staff, + active=True + ) + + retrieved_invalidation = get_certificate_invalidation_entry(certificate) + + assert retrieved_invalidation.id == invalidation.id + assert retrieved_invalidation.generated_certificate == certificate + assert retrieved_invalidation.active == invalidation.active + + def test_is_on_allowlist(self): + """ + Test to verify that we return True when an allowlist entry exists. + """ + CertificateWhitelistFactory.create(course_id=self.course_run_key, user=self.user) + + result = is_on_allowlist(self.user, self.course_run_key) + assert result + + def test_is_on_allowlist_expect_false(self): + """ + Test to verify that we will not return False when no allowlist entry exists. + """ + result = is_on_allowlist(self.user, self.course_run_key) + assert not result + + def test_is_on_allowlist_entry_disabled(self): + """ + Test to verify that we will return False when the allowlist entry if it is disabled. + """ + CertificateWhitelistFactory.create(course_id=self.course_run_key, user=self.user, whitelist=False) + + result = is_on_allowlist(self.user, self.course_run_key) + assert not result diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 5ea8d3edd8..7b6b3f4fca 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1204,7 +1204,7 @@ def _missing_required_verification(student, enrollment_mode): def _certificate_message(student, course, enrollment_mode): # lint-amnesty, pylint: disable=missing-function-docstring - if certs_api.is_certificate_invalid(student, course.id): + if certs_api.is_certificate_invalidated(student, course.id): return INVALID_CERT_DATA cert_downloadable_status = certs_api.certificate_downloadable_status(student, course.id) diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index dc4790e281..aa61e28087 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -57,8 +57,6 @@ from lms.djangoapps.bulk_email.models import BulkEmailFlag, CourseEmail, CourseE from lms.djangoapps.certificates.api import generate_user_certificates from lms.djangoapps.certificates.models import CertificateStatuses from lms.djangoapps.certificates.tests.factories import ( - CertificateInvalidationFactory, - CertificateWhitelistFactory, GeneratedCertificateFactory ) from lms.djangoapps.courseware.models import StudentModule @@ -72,8 +70,6 @@ from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag from lms.djangoapps.instructor.tests.utils import FakeContentTask, FakeEmail, FakeEmailInfo from lms.djangoapps.instructor.views.api import ( - _check_if_learner_on_allowlist, - _check_if_learner_on_blocklist, _get_certificate_for_user, _get_student_from_request_data, _split_input_list, @@ -4440,10 +4436,7 @@ class TestInstructorCertificateExceptions(SharedModuleStoreTestCase): ) retrieved_certificate = _get_certificate_for_user(self.course.id, self.user) - assert retrieved_certificate.id == generated_certificate.id - assert retrieved_certificate.user == self.user - assert retrieved_certificate.course_id == self.course.id def test_get_certificate_for_user_no_certificate(self): """ @@ -4457,89 +4450,3 @@ class TestInstructorCertificateExceptions(SharedModuleStoreTestCase): f"The student {self.user} does not have certificate for the course {self.course.id.course}. Kindly " "verify student username/email and the selected course are correct and try again." ) - - def test_check_if_learner_on_allowlist(self): - """ - Test to verify that no learner is returned if the learner does not have an active entry on the allowlist. - """ - result = _check_if_learner_on_allowlist(self.course.id, self.user) - - assert not result - - def test_check_if_learner_on_allowlist_allowlist_entry_exists(self): - """ - Test that verifies the correct result is returned if a learner has an active entry on the allowlist. - """ - CertificateWhitelistFactory.create( - course_id=self.course.id, - user=self.user - ) - - result = _check_if_learner_on_allowlist(self.course.id, self.user) - - assert result - - def test_check_if_learner_on_blocklist_no_cert(self): - """ - Test to verify that the correct result is returned if a learner does not currently have a certificate in a - course-run. - """ - result = _check_if_learner_on_blocklist(self.course.id, self.user) - - assert not result - - def test_check_if_learner_on_blocklist_with_cert(self): - """ - Test to verify that the correct result is returned if a learner has a certificate but does not have an active - entry on the blocklist. - """ - GeneratedCertificateFactory.create( - user=self.user, - course_id=self.course.id, - mode='verified', - status=CertificateStatuses.downloadable, - ) - - result = _check_if_learner_on_blocklist(self.course.id, self.user) - assert not result - - def test_check_if_learner_on_blocklist_blocklist_entry_exists(self): - """ - Test to verify that the correct result is returned if a learner has a Certificate and an active entry on - the blocklist. - """ - generated_certificate = GeneratedCertificateFactory.create( - user=self.user, - course_id=self.course.id, - mode='verified', - status=CertificateStatuses.downloadable, - ) - - CertificateInvalidationFactory.create( - generated_certificate=generated_certificate, - invalidated_by=self.global_staff, - active=True - ) - - result = _check_if_learner_on_blocklist(self.course.id, self.user) - assert result - - def test_check_if_learner_on_blocklist_inactive_blocklist_entry_exists(self): - """ - Test to verify that the correct result is returned if a learner has an inactive entry on the blocklist. - """ - generated_certificate = GeneratedCertificateFactory.create( - user=self.user, - course_id=self.course.id, - mode='verified', - status=CertificateStatuses.downloadable, - ) - - CertificateInvalidationFactory.create( - generated_certificate=generated_certificate, - invalidated_by=self.global_staff, - active=False - ) - - result = _check_if_learner_on_blocklist(self.course.id, self.user) - assert not result diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 0008b01312..770ec7171e 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -73,10 +73,8 @@ from lms.djangoapps.bulk_email.api import is_bulk_email_feature_enabled from lms.djangoapps.bulk_email.models import CourseEmail from lms.djangoapps.certificates import api as certs_api from lms.djangoapps.certificates.models import ( - CertificateInvalidation, CertificateStatuses, - CertificateWhitelist, - GeneratedCertificate + CertificateWhitelist ) from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.courses import get_course_by_id, get_course_with_access @@ -2655,41 +2653,35 @@ def add_certificate_exception(course_key, student, certificate_exception): :param certificate_exception: A dict object containing certificate exception info. :return: CertificateWhitelist item in dict format containing certificate exception info. """ - if _check_if_learner_on_blocklist(course_key, student): + # Check if the learner is blocked from receiving certificates in this course run. + if certs_api.is_certificate_invalidated(student, course_key): raise ValueError( _("Student {user} is already on the certificate invalidation list and cannot be added to the certificate " "exception list.").format(user=student.username) ) - if CertificateWhitelist.get_certificate_white_list(course_key, student): + if certs_api.is_on_allowlist(student, course_key): raise ValueError( _("Student (username/email={user}) already in certificate exception list.").format(user=student.username) ) - certificate_white_list, __ = CertificateWhitelist.objects.get_or_create( - user=student, - course_id=course_key, - defaults={ - 'whitelist': True, - 'notes': certificate_exception.get('notes', '') - } + certificate_allowlist_entry = certs_api.create_certificate_allowlist_entry( + student, + course_key, + certificate_exception.get("notes", "") ) log.info(f"Student {student.id} has been added to the whitelist in course {course_key}") - generated_certificate = GeneratedCertificate.eligible_certificates.filter( - user=student, - course_id=course_key, - status=CertificateStatuses.downloadable, - ).first() + generated_certificate = certs_api.get_certificate_for_user(student.username, course_key, False) exception = dict({ - 'id': certificate_white_list.id, + 'id': certificate_allowlist_entry.id, 'user_email': student.email, 'user_name': student.username, 'user_id': student.id, 'certificate_generated': generated_certificate and generated_certificate.created_date.strftime("%B %d, %Y"), - 'created': certificate_white_list.created.strftime("%A, %B %d, %Y"), + 'created': certificate_allowlist_entry.created.strftime("%A, %B %d, %Y"), }) return exception @@ -2706,7 +2698,7 @@ def remove_certificate_exception(course_key, student): :return: """ try: - certificate_exception = CertificateWhitelist.objects.get(user=student, course_id=course_key) + certificate_exception = certs_api.get_allowlist_entry(student, course_key) except ObjectDoesNotExist: raise ValueError( # lint-amnesty, pylint: disable=raise-missing-from _('Certificate exception (user={user}) does not exist in certificate white list. ' @@ -2714,20 +2706,17 @@ def remove_certificate_exception(course_key, student): ) try: - generated_certificate = GeneratedCertificate.objects.get( - user=student, - course_id=course_key - ) - generated_certificate.invalidate() + certificate = certs_api.get_certificate_for_user(student.username, course_key, False) log.info( - 'Certificate invalidated for %s in course %s when removed from certificate exception list', - student.username, - course_key + f"Invalidating certificate for student {student.id} in course {course_key} before removing them from the " + "allowlist." ) + certificate.invalidate() except ObjectDoesNotExist: # Certificate has not been generated yet, so just remove the certificate exception from white list pass - log.info('%s has been removed from the whitelist in course %s', student.username, course_key) + + log.info(f"Removing student {student.id} from the allowlist in course {course_key}.") certificate_exception.delete() @@ -2903,10 +2892,9 @@ def generate_bulk_certificate_exceptions(request, course_id): log.info(f'Student {user} does not exist') else: # make sure learner isn't on the blocklist - if _check_if_learner_on_blocklist(course_key, user): + if certs_api.is_certificate_invalidated(user, course_key): build_row_errors('user_on_certificate_invalidation_list', user, row_num) - log.warning(f'Student {user.id} is blocked from receiving a Certificate in Course ' - f'{course_key}') + log.warning(f'Student {user.id} is blocked from receiving a Certificate in Course {course_key}') # make sure user isn't already on the exception list elif CertificateWhitelist.get_certificate_white_list(course_key, user): build_row_errors('user_already_white_listed', user, row_num) @@ -2959,7 +2947,7 @@ def certificate_invalidation_view(request, course_id): # Invalidate certificate of the given student for the course course if request.method == 'POST': try: - if _check_if_learner_on_allowlist(course_key, student): + if certs_api.is_on_allowlist(student, course_key): log.warning(f"Invalidating certificate for student {student.id} in course {course_key} failed. " "Student is currently on the allow list.") raise ValueError( @@ -2967,8 +2955,12 @@ def certificate_invalidation_view(request, course_id): "remove them from the Certificate Exception list before attempting to invalidate their " "certificate.").format(student=student, course=course_key) ) - - certificate_invalidation = invalidate_certificate(request, certificate, certificate_invalidation_data) + certificate_invalidation = invalidate_certificate( + request, + certificate, + certificate_invalidation_data, + student + ) except ValueError as error: return JsonResponse({'message': str(error)}, status=400) return JsonResponse(certificate_invalidation) @@ -2976,54 +2968,51 @@ def certificate_invalidation_view(request, course_id): # Re-Validate student certificate for the course course elif request.method == 'DELETE': try: - re_validate_certificate(request, course_key, certificate) + re_validate_certificate(request, course_key, certificate, student) except ValueError as error: return JsonResponse({'message': str(error)}, status=400) return JsonResponse({}, status=204) -def invalidate_certificate(request, generated_certificate, certificate_invalidation_data): +def invalidate_certificate(request, generated_certificate, certificate_invalidation_data, student): """ Invalidate given GeneratedCertificate and add CertificateInvalidation record for future reference or re-validation. :param request: HttpRequest object :param generated_certificate: GeneratedCertificate object, the certificate we want to invalidate :param certificate_invalidation_data: dict object containing data for CertificateInvalidation. + :param student: User object, this user is tied to the generated_certificate we are going to invalidate :return: dict object containing updated certificate invalidation data. """ - if CertificateInvalidation.get_certificate_invalidations( - generated_certificate.course_id, - generated_certificate.user, - ): + # Check if the learner already appears on the certificate invalidation list + if certs_api.is_certificate_invalidated(student, generated_certificate.course_id): raise ValueError( _("Certificate of {user} has already been invalidated. Please check your spelling and retry.").format( - user=generated_certificate.user.username, + user=student.username, ) ) - # Verify that certificate user wants to invalidate is a valid one. + # Verify that the learner's certificate is valid before invalidating if not generated_certificate.is_valid(): raise ValueError( _("Certificate for student {user} is already invalid, kindly verify that certificate was generated " - "for this student and then proceed.").format(user=generated_certificate.user.username) + "for this student and then proceed.").format(user=student.username) ) # Add CertificateInvalidation record for future reference or re-validation - certificate_invalidation, __ = CertificateInvalidation.objects.update_or_create( - generated_certificate=generated_certificate, - defaults={ - 'invalidated_by': request.user, - 'notes': certificate_invalidation_data.get("notes", ""), - 'active': True, - } + certificate_invalidation = certs_api.create_certificate_invalidation_entry( + generated_certificate, + request.user, + certificate_invalidation_data.get("notes", ""), ) - # Invalidate GeneratedCertificate + # Invalidate the certificate generated_certificate.invalidate() + return { 'id': certificate_invalidation.id, - 'user': certificate_invalidation.generated_certificate.user.username, + 'user': student.username, 'invalidated_by': certificate_invalidation.invalidated_by.username, 'created': certificate_invalidation.created.strftime("%B %d, %Y"), 'notes': certificate_invalidation.notes, @@ -3031,7 +3020,7 @@ def invalidate_certificate(request, generated_certificate, certificate_invalidat @common_exceptions_400 -def re_validate_certificate(request, course_key, generated_certificate): +def re_validate_certificate(request, course_key, generated_certificate, student): """ Remove certificate invalidation from db and start certificate generation task for this student. Raises ValueError if certificate invalidation is present. @@ -3041,16 +3030,10 @@ def re_validate_certificate(request, course_key, generated_certificate): :param generated_certificate: GeneratedCertificate object of the student for the given course """ try: - # Fetch CertificateInvalidation object - certificate_invalidation = CertificateInvalidation.objects.get(generated_certificate=generated_certificate) + certificate_invalidation = certs_api.get_certificate_invalidation_entry(generated_certificate) + certificate_invalidation.deactivate() except ObjectDoesNotExist: raise ValueError(_("Certificate Invalidation does not exist, Please refresh the page and try again.")) # lint-amnesty, pylint: disable=raise-missing-from - else: - # Deactivate certificate invalidation if it was fetched successfully. - certificate_invalidation.deactivate() - - # We need to generate certificate only for a single student here - student = certificate_invalidation.generated_certificate.user task_api.generate_certificates_for_students( request, course_key, student_set="specific_student", specific_student_id=student.id @@ -3093,10 +3076,13 @@ def _get_student_from_request_data(request_data, course_key): def _get_certificate_for_user(course_key, student): """ - Attempts to retrieve a Certificate for a learner in a given course run key. + Attempt to retrieve certificate information for a learner in a given course-run. + + Raises a ValueError if a certificate cannot be retrieved for the learner. This will prompt an informative message + to be displayed on the instructor dashboard. """ log.info(f"Retrieving certificate for student {student.id} in course {course_key}") - certificate = GeneratedCertificate.certificate_for_student(student, course_key) + certificate = certs_api.get_certificate_for_user(student.username, course_key, False) if not certificate: raise ValueError(_( "The student {student} does not have certificate for the course {course}. Kindly verify student " @@ -3105,29 +3091,3 @@ def _get_certificate_for_user(course_key, student): ) return certificate - - -def _check_if_learner_on_allowlist(course_key, student): - """ - Utility method that will try to determine if the learner is currently on the allowlist. This is a check that - occurs as part of adding a learner to the CertificateInvalidation list. - """ - log.info(f"Checking if student {student.id} is currently on the allowlist of course {course_key}") - return CertificateWhitelist.objects.filter(user=student, course_id=course_key, whitelist=True).exists() - - -def _check_if_learner_on_blocklist(course_key, student): - """ - Utility method that will try to determine if the learner is currently on the block list. This is a check that - occurs as part of adding a learner to the Allow list. - - The CertificateInvalidation model does not store a username or user id, just a reference to the id of the - invalidated Certificate. We check if the learner has a Certificate in the Course-Run and then use that to check if - the learner has an active entry on the block list. - """ - log.info(f"Checking if student {student.id} is currently on the blocklist of course {course_key}") - cert = GeneratedCertificate.certificate_for_student(student, course_key) - if cert: - return CertificateInvalidation.objects.filter(generated_certificate_id=cert.id, active=True).exists() - - return False