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.
This commit is contained in:
Justin Hynes
2021-03-02 08:38:06 -05:00
parent f1ff795271
commit 07837cf54e
5 changed files with 239 additions and 201 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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