Merge pull request #28449 from edx/ork/MICROBA-1422_override-date-on-certificate-2
feat: Display date override on certificate
This commit is contained in:
@@ -852,8 +852,15 @@ def display_date_for_certificate(course, certificate):
|
||||
Returns:
|
||||
datetime.date
|
||||
"""
|
||||
try:
|
||||
if certificate.date_override:
|
||||
return certificate.date_override.date
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
|
||||
if _course_uses_available_date(course) and course.certificate_available_date < datetime.now(UTC):
|
||||
return course.certificate_available_date
|
||||
|
||||
return certificate.modified_date
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Certificates factories
|
||||
"""
|
||||
|
||||
|
||||
import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from factory.django import DjangoModelFactory
|
||||
@@ -10,6 +11,7 @@ from factory.django import DjangoModelFactory
|
||||
from common.djangoapps.student.models import LinkedInAddToProfileConfiguration
|
||||
from lms.djangoapps.certificates.models import (
|
||||
CertificateAllowlist,
|
||||
CertificateDateOverride,
|
||||
CertificateHtmlViewConfiguration,
|
||||
CertificateInvalidation,
|
||||
CertificateStatuses,
|
||||
@@ -104,3 +106,14 @@ class LinkedInAddToProfileConfigurationFactory(DjangoModelFactory):
|
||||
|
||||
enabled = True
|
||||
company_identifier = "1337"
|
||||
|
||||
|
||||
class CertificateDateOverrideFactory(DjangoModelFactory):
|
||||
"""
|
||||
CertificateDateOverride factory
|
||||
"""
|
||||
class Meta:
|
||||
model = CertificateDateOverride
|
||||
|
||||
date = datetime.datetime(2021, 5, 11)
|
||||
reason = "Learner really wanted this on their birthday"
|
||||
|
||||
@@ -1131,6 +1131,7 @@ class MockGeneratedCertificate:
|
||||
self.status = status
|
||||
self.created_date = datetime.now(pytz.UTC)
|
||||
self.modified_date = datetime.now(pytz.UTC)
|
||||
self.date_override = None
|
||||
|
||||
def is_valid(self):
|
||||
"""
|
||||
@@ -1139,6 +1140,11 @@ class MockGeneratedCertificate:
|
||||
return self.status == CertificateStatuses.downloadable
|
||||
|
||||
|
||||
class MockCertificateDateOverride:
|
||||
def __init__(self, date=None):
|
||||
self.date = date or datetime.now(pytz.UTC)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def configure_waffle_namespace(feature_enabled):
|
||||
"""
|
||||
@@ -1221,6 +1227,12 @@ class CertificatesApiTestCase(TestCase):
|
||||
assert maybe_avail == available_date_for_certificate(self.course, self.certificate)
|
||||
assert self.certificate.modified_date == display_date_for_certificate(self.course, self.certificate)
|
||||
|
||||
# With a certificate date override, display date returns the override, available date ignores it
|
||||
self.certificate.date_override = MockCertificateDateOverride()
|
||||
date = self.certificate.date_override.date
|
||||
assert date == display_date_for_certificate(self.course, self.certificate)
|
||||
assert maybe_avail == available_date_for_certificate(self.course, self.certificate)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class CertificatesMessagingTestCase(ModuleStoreTestCase):
|
||||
|
||||
@@ -38,6 +38,7 @@ from lms.djangoapps.certificates.models import (
|
||||
GeneratedCertificate
|
||||
)
|
||||
from lms.djangoapps.certificates.tests.factories import (
|
||||
CertificateDateOverrideFactory,
|
||||
CertificateHtmlViewConfigurationFactory,
|
||||
GeneratedCertificateFactory,
|
||||
LinkedInAddToProfileConfigurationFactory
|
||||
@@ -237,6 +238,15 @@ class CommonCertificatesTestCase(ModuleStoreTestCase):
|
||||
)
|
||||
template.save()
|
||||
|
||||
def _add_certificate_date_override(self):
|
||||
"""
|
||||
Creates a mock CertificateDateOverride and adds it to the certificate
|
||||
"""
|
||||
self.cert.date_override = CertificateDateOverrideFactory.create(
|
||||
generated_certificate=self.cert,
|
||||
overridden_by=self.user,
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase):
|
||||
@@ -646,10 +656,13 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
|
||||
response = self.client.get(test_url)
|
||||
self.assertContains(response, '<html class="no-js" lang="ar">')
|
||||
|
||||
@ddt.data(False, True)
|
||||
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
|
||||
def test_html_view_for_non_viewable_certificate_and_for_student_user(self):
|
||||
def test_html_view_for_non_viewable_certificate_and_for_student_user(self, date_override):
|
||||
"""
|
||||
Tests that Certificate HTML Web View returns "Cannot Find Certificate" if certificate is not viewable yet.
|
||||
Tests that Certificate HTML Web View returns "Cannot Find Certificate"
|
||||
if certificate is not viewable yet, regardless of certificate date
|
||||
override
|
||||
"""
|
||||
test_certificates = [
|
||||
{
|
||||
@@ -660,6 +673,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
# A certificate with an available date in the future should not be
|
||||
# viewable, regardless of the date override.
|
||||
if date_override:
|
||||
self._add_certificate_date_override()
|
||||
|
||||
self.course.certificates = {'certificates': test_certificates}
|
||||
self.course.cert_html_view_enabled = True
|
||||
self.course.certificate_available_date = datetime.datetime.today() + datetime.timedelta(days=1)
|
||||
@@ -945,6 +964,54 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
|
||||
)
|
||||
self.assertContains(response, date)
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
|
||||
@ddt.data(
|
||||
(True, False),
|
||||
(False, False),
|
||||
(True, True),
|
||||
(False, True)
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_html_view_certificate_display_date(self, self_paced, date_override):
|
||||
"""
|
||||
Test certificate web view should display the correct date on the
|
||||
certificate in all cases:
|
||||
* self-paced, no date override
|
||||
* instructor-paced with certificate_available_date
|
||||
* self-paced with date override
|
||||
* instructor-paced with date override
|
||||
"""
|
||||
self.course.self_paced = self_paced
|
||||
if date_override:
|
||||
self._add_certificate_date_override()
|
||||
today = datetime.datetime.utcnow()
|
||||
self.course.certificate_available_date = today + datetime.timedelta(-2)
|
||||
self.store.update_item(self.course, self.user.id)
|
||||
self._add_course_certificates(count=1, signatory_count=1, is_active=True)
|
||||
test_url = get_certificate_url(
|
||||
user_id=self.user.id,
|
||||
course_id=str(self.course.id),
|
||||
uuid=self.cert.verify_uuid
|
||||
)
|
||||
|
||||
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION, active=True):
|
||||
response = self.client.get(test_url)
|
||||
|
||||
if date_override:
|
||||
expected_date = self.cert.date_override.date
|
||||
elif self_paced or self.course.certificate_available_date > today:
|
||||
expected_date = today
|
||||
else:
|
||||
expected_date = self.course.certificate_available_date
|
||||
|
||||
date = '{month} {day}, {year}'.format(
|
||||
month=strftime_localized(expected_date, "%B"),
|
||||
day=expected_date.day,
|
||||
year=expected_date.year
|
||||
)
|
||||
|
||||
self.assertContains(response, date)
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
|
||||
def test_render_html_view_invalid_certificate_configuration(self):
|
||||
self.course.cert_html_view_enabled = True
|
||||
|
||||
Reference in New Issue
Block a user