Revert "feat: Reimagine certificate_availability_date and certificates_display_behavior"
This commit is contained in:
@@ -49,7 +49,6 @@ from lms.djangoapps.verify_student.utils import is_verification_expiring_soon, v
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.theming.helpers import get_themes
|
||||
from openedx.core.djangoapps.user_authn.utils import is_safe_login_or_logout_redirect
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
|
||||
# Enumeration of per-course verification statuses
|
||||
# we display on the student dashboard.
|
||||
@@ -512,17 +511,14 @@ def _cert_info(user, course_overview, cert_status):
|
||||
is_hidden_status = status in ('processing', 'generating', 'notpassing', 'auditing')
|
||||
|
||||
if (
|
||||
not certificates_viewable_for_course(course_overview)
|
||||
and CertificateStatuses.is_passing_status(status)
|
||||
and course_overview.certificates_display_behavior in (
|
||||
CertificatesDisplayBehaviors.END_WITH_DATE,
|
||||
CertificatesDisplayBehaviors.END
|
||||
)
|
||||
not certificates_viewable_for_course(course_overview) and
|
||||
CertificateStatuses.is_passing_status(status) and
|
||||
course_overview.certificate_available_date
|
||||
):
|
||||
status = certificate_earned_but_not_available_status
|
||||
|
||||
if (
|
||||
course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.EARLY_NO_INFO and
|
||||
course_overview.certificates_display_behavior == 'early_no_info' and
|
||||
is_hidden_status
|
||||
):
|
||||
return default_info
|
||||
|
||||
@@ -22,7 +22,6 @@ from lms.djangoapps.certificates.tests.factories import (
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
|
||||
# pylint: disable=no-member
|
||||
|
||||
@@ -41,7 +40,7 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase):
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.course = CourseFactory()
|
||||
cls.course.certificates_display_behavior = CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
cls.course.certificates_display_behavior = "early_with_info"
|
||||
|
||||
with cls.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, cls.course.id):
|
||||
cls.store.update_item(cls.course, cls.USERNAME)
|
||||
@@ -117,54 +116,40 @@ class CertificateDashboardMessageDisplayTest(CertificateDisplayTestBase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.course.certificates_display_behavior = CertificatesDisplayBehaviors.END_WITH_DATE
|
||||
cls.course.certificates_display_behavior = "end"
|
||||
cls.course.save()
|
||||
cls.store.update_item(cls.course, cls.USERNAME)
|
||||
|
||||
def _check_message(self, visible_date): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
def _check_message(self, certificate_available_date): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
test_message = 'Your grade and certificate will be ready after'
|
||||
|
||||
is_past = visible_date < datetime.datetime.now(UTC)
|
||||
|
||||
if is_past:
|
||||
if certificate_available_date is None:
|
||||
self.assertNotContains(response, test_message)
|
||||
self.assertNotContains(response, "View Test_Certificate")
|
||||
self._check_can_download_certificate()
|
||||
|
||||
else:
|
||||
elif datetime.datetime.now(UTC) < certificate_available_date:
|
||||
self.assertContains(response, test_message)
|
||||
self.assertNotContains(response, "View Test_Certificate")
|
||||
else:
|
||||
self._check_can_download_certificate()
|
||||
|
||||
@ddt.data(
|
||||
(CertificatesDisplayBehaviors.END, True),
|
||||
(CertificatesDisplayBehaviors.END, False),
|
||||
(CertificatesDisplayBehaviors.END_WITH_DATE, True),
|
||||
(CertificatesDisplayBehaviors.END_WITH_DATE, False)
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_certificate_available_date(self, certificates_display_behavior, past_date):
|
||||
@ddt.data(True, False, None)
|
||||
def test_certificate_available_date(self, past_certificate_available_date):
|
||||
cert = self._create_certificate('verified')
|
||||
cert.status = CertificateStatuses.downloadable
|
||||
cert.save()
|
||||
|
||||
self.course.certificates_display_behavior = certificates_display_behavior
|
||||
|
||||
if certificates_display_behavior == CertificatesDisplayBehaviors.END:
|
||||
if past_date:
|
||||
self.course.end = PAST_DATE
|
||||
else:
|
||||
self.course.end = FUTURE_DATE
|
||||
if certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE:
|
||||
if past_date:
|
||||
self.course.certificate_available_date = PAST_DATE
|
||||
else:
|
||||
self.course.certificate_available_date = FUTURE_DATE
|
||||
if past_certificate_available_date is None:
|
||||
certificate_available_date = None
|
||||
elif past_certificate_available_date:
|
||||
certificate_available_date = PAST_DATE
|
||||
elif not past_certificate_available_date:
|
||||
certificate_available_date = FUTURE_DATE
|
||||
|
||||
self.course.certificate_available_date = certificate_available_date
|
||||
self.course.save()
|
||||
self.store.update_item(self.course, self.USERNAME)
|
||||
|
||||
self._check_message(PAST_DATE if past_date else FUTURE_DATE)
|
||||
self._check_message(certificate_available_date)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
||||
@@ -40,7 +40,6 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou
|
||||
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context
|
||||
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
|
||||
from openedx.features.course_experience.tests.views.helpers import add_course_mode
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
@@ -228,7 +227,6 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
id=course_key,
|
||||
end_date=THREE_YEARS_AGO,
|
||||
certificate_available_date=TOMORROW,
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END_WITH_DATE,
|
||||
lowest_passing_grade=0.3
|
||||
)
|
||||
CourseEnrollmentFactory(course_id=course.id, user=self.user)
|
||||
@@ -244,7 +242,6 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
id=course_key,
|
||||
end_date=TOMORROW,
|
||||
certificate_available_date=TOMORROW,
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END_WITH_DATE,
|
||||
lowest_passing_grade=0.3
|
||||
)
|
||||
CourseEnrollmentFactory(course_id=course.id, user=self.user)
|
||||
@@ -260,7 +257,6 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
id=course_key,
|
||||
end_date=ONE_WEEK_AGO,
|
||||
certificate_available_date=now(),
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END_WITH_DATE,
|
||||
lowest_passing_grade=0.3
|
||||
)
|
||||
CourseEnrollmentFactory(course_id=course.id, user=self.user)
|
||||
|
||||
@@ -49,8 +49,6 @@ from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreEnum, ModuleStoreTestCase, SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -77,8 +75,7 @@ class CourseEndingTest(ModuleStoreTestCase):
|
||||
survey_url = "http://a_survey.com"
|
||||
course = CourseOverviewFactory.create(
|
||||
end_of_course_survey_url=survey_url,
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END,
|
||||
end=datetime.now(pytz.UTC) - timedelta(days=2)
|
||||
certificates_display_behavior='end',
|
||||
)
|
||||
cert = GeneratedCertificateFactory.create(
|
||||
user=user,
|
||||
@@ -141,7 +138,7 @@ class CourseEndingTest(ModuleStoreTestCase):
|
||||
'can_unenroll': True}
|
||||
|
||||
# test when the display is unavailable or notpassing, we get the correct results out
|
||||
course2.certificates_display_behavior = CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
course2.certificates_display_behavior = 'early_no_info'
|
||||
cert_status = {'status': 'unavailable', 'mode': 'honor', 'uuid': None}
|
||||
assert _cert_info(user, course2, cert_status) == {'status': 'processing', 'show_survey_button': False,
|
||||
'can_unenroll': True}
|
||||
@@ -176,8 +173,7 @@ class CourseEndingTest(ModuleStoreTestCase):
|
||||
survey_url = "http://a_survey.com"
|
||||
course = CourseOverviewFactory.create(
|
||||
end_of_course_survey_url=survey_url,
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END,
|
||||
end=datetime.now(pytz.UTC) - timedelta(days=2),
|
||||
certificates_display_behavior='end',
|
||||
)
|
||||
|
||||
if cert_grade is not None:
|
||||
@@ -202,8 +198,7 @@ class CourseEndingTest(ModuleStoreTestCase):
|
||||
survey_url = "http://a_survey.com"
|
||||
course = CourseOverviewFactory.create(
|
||||
end_of_course_survey_url=survey_url,
|
||||
certificates_display_behavior=CertificatesDisplayBehaviors.END,
|
||||
end=datetime.now(pytz.UTC) - timedelta(days=2),
|
||||
certificates_display_behavior='end',
|
||||
)
|
||||
cert_status = {'status': 'generating', 'mode': 'honor', 'uuid': None}
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ from math import exp
|
||||
import dateutil.parser
|
||||
from pytz import utc
|
||||
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
|
||||
DEFAULT_START_DATE = datetime(2030, 1, 1, tzinfo=utc)
|
||||
|
||||
"""
|
||||
@@ -158,18 +156,15 @@ def may_certify_for_course(
|
||||
self_paced (bool): Whether the course is self-paced.
|
||||
"""
|
||||
show_early = (
|
||||
certificates_display_behavior == CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
certificates_display_behavior in ('early_with_info', 'early_no_info')
|
||||
or certificates_show_before_end
|
||||
)
|
||||
past_available_date = (
|
||||
certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE
|
||||
and certificate_available_date
|
||||
certificate_available_date
|
||||
and certificate_available_date < datetime.now(utc)
|
||||
)
|
||||
ended_without_available_date = (
|
||||
certificates_display_behavior == CertificatesDisplayBehaviors.END
|
||||
and has_ended
|
||||
)
|
||||
ended_without_available_date = (certificate_available_date is None) and has_ended
|
||||
|
||||
return any((self_paced, show_early, past_available_date, ended_without_available_date))
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Django module container for classes and operations related to the "Course Module
|
||||
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from io import BytesIO
|
||||
|
||||
import dateutil.parser
|
||||
@@ -22,7 +22,6 @@ from openedx.core.lib.license import LicenseMixin
|
||||
from openedx.core.lib.teams_config import TeamsConfig # lint-amnesty, pylint: disable=unused-import
|
||||
from xmodule import course_metadata_utils
|
||||
from xmodule.course_metadata_utils import DEFAULT_GRADING_POLICY, DEFAULT_START_DATE
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
from xmodule.graders import grader_from_conf
|
||||
from xmodule.seq_module import SequenceBlock
|
||||
from xmodule.tabs import CourseTabList, InvalidTabsException
|
||||
@@ -556,15 +555,15 @@ class CourseFields: # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
certificates_display_behavior = String(
|
||||
display_name=_("Certificates Display Behavior"),
|
||||
help=_(
|
||||
"Enter end, end_with_date, or early_no_info. After certificate generation, students who passed see a "
|
||||
"Enter end, early_with_info, or early_no_info. After certificate generation, students who passed see a "
|
||||
"link to their certificates on the dashboard and students who did not pass see information about the "
|
||||
"grading configuration. The default is end, which displays this certificate information to all students "
|
||||
"after the course end date. To display the certificate information to all students at a date after the "
|
||||
"course end date, use end_with_date and add a certificate_available_date. To display only the links to "
|
||||
"passing students as soon as certificates are generated, enter early_no_info."
|
||||
"after the course end date. To display this certificate information to all students as soon as "
|
||||
"certificates are generated, enter early_with_info. To display only the links to passing students as "
|
||||
"soon as certificates are generated, enter early_no_info."
|
||||
),
|
||||
scope=Scope.settings,
|
||||
default=CertificatesDisplayBehaviors.END,
|
||||
default="end"
|
||||
)
|
||||
course_image = String(
|
||||
display_name=_("Course About Page Image"),
|
||||
@@ -1062,6 +1061,8 @@ class CourseBlock(
|
||||
except InvalidTabsException as err:
|
||||
raise type(err)(f'{str(err)} For course: {str(self.id)}') # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
self.set_default_certificate_available_date()
|
||||
|
||||
def set_grading_policy(self, course_policy):
|
||||
"""
|
||||
The JSON object can have the keys GRADER and GRADE_CUTOFFS. If either is
|
||||
@@ -1087,6 +1088,10 @@ class CourseBlock(
|
||||
self.raw_grader = grading_policy['GRADER'] # used for cms access
|
||||
self.grade_cutoffs = grading_policy['GRADE_CUTOFFS']
|
||||
|
||||
def set_default_certificate_available_date(self):
|
||||
if (not self.certificate_available_date) and self.end:
|
||||
self.certificate_available_date = self.end + timedelta(days=2)
|
||||
|
||||
@classmethod
|
||||
def read_grading_policy(cls, paths, system):
|
||||
"""Load a grading policy from the specified paths, in order, if it exists."""
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
"""
|
||||
Public data structures for this app.
|
||||
|
||||
See OEP-49 for details
|
||||
"""
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class CertificatesDisplayBehaviors(str, Enum):
|
||||
"""
|
||||
Options for the certificates_display_behavior field of a course
|
||||
|
||||
end: Certificates are available at the end of the course
|
||||
end_with_date: Certificates are available after the certificate_available_date (post course end)
|
||||
early_no_info: Certificates are available immediately after earning them.
|
||||
|
||||
Only in affect for instructor based courses.
|
||||
"""
|
||||
END = "end"
|
||||
END_WITH_DATE = "end_with_date"
|
||||
EARLY_NO_INFO = "early_no_info"
|
||||
|
||||
@classmethod
|
||||
def includes_value(cls, value):
|
||||
return value in set(item.value for item in cls)
|
||||
@@ -23,7 +23,6 @@ from xmodule.course_metadata_utils import (
|
||||
may_certify_for_course,
|
||||
number_for_course_location
|
||||
)
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
from xmodule.modulestore.tests.utils import (
|
||||
MixedModulestoreBuilder,
|
||||
MongoModulestoreBuilder,
|
||||
@@ -164,28 +163,16 @@ class CourseMetadataUtilsTestCase(TestCase):
|
||||
TestScenario((DEFAULT_START_DATE, None), True),
|
||||
]),
|
||||
FunctionTest(may_certify_for_course, [
|
||||
# Test certificates_show_before_end
|
||||
TestScenario((CertificatesDisplayBehaviors.EARLY_NO_INFO, True, False, test_datetime, False), True),
|
||||
TestScenario((CertificatesDisplayBehaviors.END, True, False, test_datetime, False), True),
|
||||
TestScenario((CertificatesDisplayBehaviors.END_WITH_DATE, True, False, _NEXT_WEEK, False), True),
|
||||
|
||||
# Test that EARLY_NO_INFO
|
||||
TestScenario((CertificatesDisplayBehaviors.EARLY_NO_INFO, True, True, test_datetime, False), True),
|
||||
TestScenario((CertificatesDisplayBehaviors.EARLY_NO_INFO, False, False, test_datetime, False), True),
|
||||
|
||||
# Test END_WITH_DATE
|
||||
TestScenario((CertificatesDisplayBehaviors.END_WITH_DATE, False, False, test_datetime, False), True),
|
||||
TestScenario((CertificatesDisplayBehaviors.END_WITH_DATE, False, False, _LAST_WEEK, False), True),
|
||||
TestScenario((CertificatesDisplayBehaviors.END_WITH_DATE, False, False, _NEXT_WEEK, False), False),
|
||||
TestScenario((CertificatesDisplayBehaviors.END_WITH_DATE, False, False, None, False), False),
|
||||
|
||||
# Test END
|
||||
TestScenario((CertificatesDisplayBehaviors.END, False, False, test_datetime, False), False),
|
||||
TestScenario((CertificatesDisplayBehaviors.END, False, True, test_datetime, False), True),
|
||||
|
||||
# Test self_paced
|
||||
TestScenario((CertificatesDisplayBehaviors.END, False, False, test_datetime, False), False),
|
||||
TestScenario((CertificatesDisplayBehaviors.END, False, False, test_datetime, True), True),
|
||||
TestScenario(('early_with_info', True, True, test_datetime, False), True),
|
||||
TestScenario(('early_no_info', False, False, test_datetime, False), True),
|
||||
TestScenario(('end', True, False, test_datetime, False), True),
|
||||
TestScenario(('end', False, True, test_datetime, False), True),
|
||||
TestScenario(('end', False, False, _NEXT_WEEK, False), False),
|
||||
TestScenario(('end', False, False, _LAST_WEEK, False), True),
|
||||
TestScenario(('end', False, False, None, False), False),
|
||||
TestScenario(('early_with_info', False, False, None, False), True),
|
||||
TestScenario(('end', False, False, _NEXT_WEEK, False), False),
|
||||
TestScenario(('end', False, False, _NEXT_WEEK, True), True),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ from xblock.runtime import DictKeyValueStore, KvsFieldData
|
||||
|
||||
from openedx.core.lib.teams_config import TeamsConfig, DEFAULT_COURSE_RUN_MAX_TEAM_SIZE
|
||||
import xmodule.course_module
|
||||
from xmodule.data import CertificatesDisplayBehaviors
|
||||
from xmodule.modulestore.xml import ImportSystem, XMLModuleStore
|
||||
from xmodule.modulestore.exceptions import InvalidProctoringProvider
|
||||
|
||||
@@ -106,41 +105,36 @@ class HasEndedMayCertifyTestCase(unittest.TestCase):
|
||||
super().setUp()
|
||||
|
||||
system = DummySystem(load_error_modules=True) # lint-amnesty, pylint: disable=unused-variable
|
||||
|
||||
#sample_xml = """
|
||||
# <course org="{org}" course="{course}" display_organization="{org}_display" display_coursenumber="{course}_display" # lint-amnesty, pylint: disable=line-too-long
|
||||
# graceperiod="1 day" url_name="test"
|
||||
# start="2012-01-01T12:00"
|
||||
# {end}
|
||||
# certificates_show_before_end={cert}>
|
||||
# <chapter url="hi" url_name="ch" display_name="CH">
|
||||
# <html url_name="h" display_name="H">Two houses, ...</html>
|
||||
# </chapter>
|
||||
# </course>
|
||||
#""".format(org=ORG, course=COURSE)
|
||||
past_end = (datetime.now() - timedelta(days=12)).strftime("%Y-%m-%dT%H:%M:00")
|
||||
future_end = (datetime.now() + timedelta(days=12)).strftime("%Y-%m-%dT%H:%M:00")
|
||||
self.past_show_certs = get_dummy_course(
|
||||
"2012-01-01T12:00",
|
||||
end=past_end,
|
||||
certs=CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
)
|
||||
self.past_show_certs_no_info = get_dummy_course(
|
||||
"2012-01-01T12:00",
|
||||
end=past_end,
|
||||
certs=CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
)
|
||||
self.past_noshow_certs = get_dummy_course(
|
||||
"2012-01-01T12:00",
|
||||
end=past_end,
|
||||
certs=CertificatesDisplayBehaviors.END
|
||||
)
|
||||
|
||||
self.future_show_certs_no_info = get_dummy_course(
|
||||
"2012-01-01T12:00",
|
||||
end=future_end,
|
||||
certs=CertificatesDisplayBehaviors.EARLY_NO_INFO
|
||||
)
|
||||
self.future_noshow_certs = get_dummy_course(
|
||||
"2012-01-01T12:00",
|
||||
end=future_end,
|
||||
certs=CertificatesDisplayBehaviors.END
|
||||
)
|
||||
self.past_show_certs = get_dummy_course("2012-01-01T12:00", end=past_end, certs='early_with_info')
|
||||
self.past_show_certs_no_info = get_dummy_course("2012-01-01T12:00", end=past_end, certs='early_no_info')
|
||||
self.past_noshow_certs = get_dummy_course("2012-01-01T12:00", end=past_end, certs='end')
|
||||
self.future_show_certs = get_dummy_course("2012-01-01T12:00", end=future_end, certs='early_with_info')
|
||||
self.future_show_certs_no_info = get_dummy_course("2012-01-01T12:00", end=future_end, certs='early_no_info')
|
||||
self.future_noshow_certs = get_dummy_course("2012-01-01T12:00", end=future_end, certs='end')
|
||||
#self.past_show_certs = system.process_xml(sample_xml.format(end=past_end, cert=True))
|
||||
#self.past_noshow_certs = system.process_xml(sample_xml.format(end=past_end, cert=False))
|
||||
#self.future_show_certs = system.process_xml(sample_xml.format(end=future_end, cert=True))
|
||||
#self.future_noshow_certs = system.process_xml(sample_xml.format(end=future_end, cert=False))
|
||||
|
||||
def test_has_ended(self):
|
||||
"""Check that has_ended correctly tells us when a course is over."""
|
||||
assert self.past_show_certs.has_ended()
|
||||
assert self.past_show_certs_no_info.has_ended()
|
||||
assert self.past_noshow_certs.has_ended()
|
||||
assert not self.future_show_certs.has_ended()
|
||||
assert not self.future_show_certs_no_info.has_ended()
|
||||
assert not self.future_noshow_certs.has_ended()
|
||||
|
||||
@@ -149,6 +143,7 @@ class HasEndedMayCertifyTestCase(unittest.TestCase):
|
||||
assert self.past_show_certs.may_certify()
|
||||
assert self.past_noshow_certs.may_certify()
|
||||
assert self.past_show_certs_no_info.may_certify()
|
||||
assert self.future_show_certs.may_certify()
|
||||
assert self.future_show_certs_no_info.may_certify()
|
||||
assert not self.future_noshow_certs.may_certify()
|
||||
|
||||
@@ -416,6 +411,14 @@ class CourseBlockTestCase(unittest.TestCase):
|
||||
"""
|
||||
assert self.course.number == COURSE
|
||||
|
||||
def test_set_default_certificate_available_date(self):
|
||||
"""
|
||||
The certificate_available_date field should default to two days
|
||||
after the course end date.
|
||||
"""
|
||||
expected_certificate_available_date = self.course.end + timedelta(days=2)
|
||||
assert expected_certificate_available_date == self.course.certificate_available_date
|
||||
|
||||
|
||||
class ProctoringProviderTestCase(unittest.TestCase):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user