write tests for when verified mode expires
This commit is contained in:
@@ -364,26 +364,35 @@ def get_expiration_banner_text(user, course):
|
||||
upgrade_link = verified_upgrade_deadline_link(user=user, course=course)
|
||||
enrollment = CourseEnrollment.get_enrollment(user, course.id)
|
||||
upgrade_deadline = enrollment.upgrade_deadline
|
||||
if upgrade_deadline is None:
|
||||
return
|
||||
if now() < upgrade_deadline:
|
||||
if upgrade_deadline is None or now() < upgrade_deadline:
|
||||
upgrade_deadline = enrollment.course_upgrade_deadline
|
||||
|
||||
language = get_language()
|
||||
if language and language.split('-')[0].lower() == 'es':
|
||||
language_is_es = language and language.split('-')[0].lower() == 'es'
|
||||
if language_is_es:
|
||||
formatted_expiration_date = strftime_localized(expiration_date, '%-d de %b. de %Y').lower()
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%-d de %b. de %Y').lower()
|
||||
else:
|
||||
formatted_expiration_date = strftime_localized(expiration_date, '%b. %-d, %Y')
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%b. %-d, %Y')
|
||||
|
||||
bannerText = '<strong>Audit Access Expires {expiration_date}</strong><br>\
|
||||
You lose all access to this course, including your progress, on {expiration_date}.<br>\
|
||||
Upgrade by {upgrade_deadline} to get unlimited access to the course as long as it exists on the site.\
|
||||
<a href="{upgrade_link}">Upgrade now<span class="sr-only"> to retain access past {expiration_date}\
|
||||
</span></a>'.format(
|
||||
expiration_date=formatted_expiration_date,
|
||||
upgrade_link=upgrade_link,
|
||||
upgrade_deadline=formatted_upgrade_deadline
|
||||
)
|
||||
if upgrade_deadline:
|
||||
if language_is_es:
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%-d de %b. de %Y').lower()
|
||||
else:
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%b. %-d, %Y')
|
||||
|
||||
bannerText = '<strong>Audit Access Expires {expiration_date}</strong><br>\
|
||||
You lose all access to this course, including your progress, on {expiration_date}.\
|
||||
<br>Upgrade by {upgrade_deadline} to get unlimited access to the course as long as it exists\
|
||||
on the site. <a href="{upgrade_link}">Upgrade now<span class="sr-only"> to retain access past\
|
||||
{expiration_date}</span></a>'.format(
|
||||
expiration_date=formatted_expiration_date,
|
||||
upgrade_link=upgrade_link,
|
||||
upgrade_deadline=formatted_upgrade_deadline
|
||||
)
|
||||
else:
|
||||
bannerText = '<strong>Audit Access Expires {expiration_date}</strong><br>\
|
||||
You lose all access to this course, including your progress, on {expiration_date}.\
|
||||
'.format(
|
||||
expiration_date=formatted_expiration_date
|
||||
)
|
||||
return bannerText
|
||||
|
||||
@@ -35,7 +35,11 @@ from lms.djangoapps.courseware.tests.factories import (
|
||||
from openedx.core.djangoapps.user_api.tests.factories import UserCourseTagFactory
|
||||
from openedx.core.djangoapps.util.testing import TestConditionalContent
|
||||
from openedx.core.lib.url_utils import quote_slashes
|
||||
from openedx.features.content_type_gating.partitions import CONTENT_GATING_PARTITION_ID, CONTENT_TYPE_GATE_GROUP_IDS
|
||||
from openedx.features.content_type_gating.partitions import (
|
||||
CONTENT_GATING_PARTITION_ID,
|
||||
CONTENT_TYPE_GATE_GROUP_IDS,
|
||||
ContentTypeGatingPartition
|
||||
)
|
||||
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
|
||||
from openedx.features.course_duration_limits.config import (
|
||||
EXPERIMENT_ID,
|
||||
@@ -89,7 +93,7 @@ def _get_fragment_from_block(block, user_id, course, request_factory, mock_get_c
|
||||
return frag
|
||||
|
||||
|
||||
def _assert_block_is_gated(block, is_gated, user_id, course, request_factory):
|
||||
def _assert_block_is_gated(block, is_gated, user_id, course, request_factory, has_upgrade_link=True):
|
||||
"""
|
||||
Asserts that a block in a specific course is gated for a specific user
|
||||
Arguments:
|
||||
@@ -98,9 +102,15 @@ def _assert_block_is_gated(block, is_gated, user_id, course, request_factory):
|
||||
user_id (int): id of user
|
||||
course_id (CourseLocator): id of course
|
||||
"""
|
||||
frag = _get_fragment_from_block(block, user_id, course, request_factory)
|
||||
checkout_link = '#' if has_upgrade_link else None
|
||||
with patch.object(ContentTypeGatingPartition, '_get_checkout_link', return_value=checkout_link):
|
||||
frag = _get_fragment_from_block(block, user_id, course, request_factory)
|
||||
if is_gated:
|
||||
assert 'content-paywall' in frag.content
|
||||
if has_upgrade_link:
|
||||
assert 'certA_1' in frag.content
|
||||
else:
|
||||
assert 'certA_1' not in frag.content
|
||||
else:
|
||||
assert 'content-paywall' not in frag.content
|
||||
|
||||
@@ -236,6 +246,18 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
||||
component_types=['problem', 'html']
|
||||
)
|
||||
|
||||
cls.courses['expired_upgrade_deadline'] = cls._create_course(
|
||||
run='expired_upgrade_deadline_run_1',
|
||||
display_name='Expired Upgrade Deadline Course Title',
|
||||
modes=['audit'],
|
||||
component_types=['problem', 'html']
|
||||
)
|
||||
CourseModeFactory.create(
|
||||
course_id=cls.courses['expired_upgrade_deadline']['course'].scope_ids.usage_id.course_key,
|
||||
mode_slug='verified',
|
||||
expiration_datetime=datetime(2018, 1, 1)
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super(TestProblemTypeAccess, self).setUp()
|
||||
|
||||
@@ -266,6 +288,12 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
||||
course_id=self.courses['audit_only']['course'].id,
|
||||
mode='audit'
|
||||
)
|
||||
# enroll audit user into the upgrade expired course
|
||||
CourseEnrollmentFactory.create(
|
||||
user=self.audit_user,
|
||||
course_id=self.courses['expired_upgrade_deadline']['course'].id,
|
||||
mode='audit'
|
||||
)
|
||||
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
|
||||
|
||||
@classmethod
|
||||
@@ -406,6 +434,20 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
||||
request_factory=self.factory,
|
||||
)
|
||||
|
||||
def test_access_expired_upgrade_deadline(self):
|
||||
"""
|
||||
If a user is enrolled as an audit user and the upgrade deadline has passed
|
||||
the user will continue to see gated content, but the upgrade messaging will be removed.
|
||||
"""
|
||||
_assert_block_is_gated(
|
||||
block=self.courses['default']['blocks']['problem'],
|
||||
user_id=self.users['audit'].id,
|
||||
course=self.courses['default']['course'],
|
||||
is_gated=True,
|
||||
request_factory=self.factory,
|
||||
has_upgrade_link=False
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
('problem', 'graded_problem', 'audit', 404),
|
||||
('problem', 'graded_problem', 'verified', 200),
|
||||
|
||||
@@ -66,7 +66,7 @@ def get_user_course_expiration_date(user, course):
|
||||
|
||||
access_duration = MIN_DURATION
|
||||
|
||||
if not CourseMode.verified_mode_for_course(course.id):
|
||||
if not CourseMode.verified_mode_for_course(course.id, include_expired=True):
|
||||
return None
|
||||
|
||||
enrollment = CourseEnrollment.get_enrollment(user, course.id)
|
||||
@@ -138,11 +138,9 @@ def register_course_expired_message(request, course):
|
||||
return
|
||||
|
||||
upgrade_deadline = enrollment.upgrade_deadline
|
||||
if upgrade_deadline is None:
|
||||
return
|
||||
now = timezone.now()
|
||||
course_upgrade_deadline = enrollment.course_upgrade_deadline
|
||||
if now > upgrade_deadline:
|
||||
if upgrade_deadline and now > upgrade_deadline:
|
||||
upgrade_deadline = course_upgrade_deadline
|
||||
|
||||
expiration_message = _('{strong_open}Audit Access Expires {expiration_date}{strong_close}'
|
||||
@@ -152,31 +150,47 @@ def register_course_expired_message(request, course):
|
||||
'as long as it exists on the site. {a_open}Upgrade now{sronly_span_open} to '
|
||||
'retain access past {expiration_date}{span_close}{a_close}')
|
||||
full_message = expiration_message
|
||||
if now < course_upgrade_deadline:
|
||||
if course_upgrade_deadline and now < course_upgrade_deadline:
|
||||
full_message += upgrade_deadline_message
|
||||
|
||||
language = get_language()
|
||||
if language and language.split('-')[0].lower() == 'es':
|
||||
language_is_es = language and language.split('-')[0].lower() == 'es'
|
||||
if language_is_es:
|
||||
formatted_expiration_date = strftime_localized(expiration_date, '%-d de %b. de %Y').lower()
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%-d de %b. de %Y').lower()
|
||||
else:
|
||||
formatted_expiration_date = strftime_localized(expiration_date, '%b. %-d, %Y')
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%b. %-d, %Y')
|
||||
|
||||
PageLevelMessages.register_info_message(
|
||||
request,
|
||||
Text(full_message).format(
|
||||
a_open=HTML('<a href="{upgrade_link}">').format(
|
||||
upgrade_link=verified_upgrade_deadline_link(user=request.user, course=course)
|
||||
),
|
||||
sronly_span_open=HTML('<span class="sr-only">'),
|
||||
sighted_only_span_open=HTML('<span aria-hidden="true">'),
|
||||
span_close=HTML('</span>'),
|
||||
a_close=HTML('</a>'),
|
||||
expiration_date=formatted_expiration_date,
|
||||
strong_open=HTML('<strong>'),
|
||||
strong_close=HTML('</strong>'),
|
||||
line_break=HTML('<br>'),
|
||||
upgrade_deadline=formatted_upgrade_deadline
|
||||
if upgrade_deadline:
|
||||
if language_is_es:
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%-d de %b. de %Y').lower()
|
||||
else:
|
||||
formatted_upgrade_deadline = strftime_localized(upgrade_deadline, '%b. %-d, %Y')
|
||||
|
||||
if upgrade_deadline:
|
||||
PageLevelMessages.register_info_message(
|
||||
request,
|
||||
Text(full_message).format(
|
||||
a_open=HTML('<a href="{upgrade_link}">').format(
|
||||
upgrade_link=verified_upgrade_deadline_link(user=request.user, course=course)
|
||||
),
|
||||
sronly_span_open=HTML('<span class="sr-only">'),
|
||||
span_close=HTML('</span>'),
|
||||
a_close=HTML('</a>'),
|
||||
expiration_date=formatted_expiration_date,
|
||||
strong_open=HTML('<strong>'),
|
||||
strong_close=HTML('</strong>'),
|
||||
line_break=HTML('<br>'),
|
||||
upgrade_deadline=formatted_upgrade_deadline
|
||||
)
|
||||
)
|
||||
else:
|
||||
PageLevelMessages.register_info_message(
|
||||
request,
|
||||
Text(full_message).format(
|
||||
span_close=HTML('</span>'),
|
||||
expiration_date=formatted_expiration_date,
|
||||
strong_open=HTML('<strong>'),
|
||||
strong_close=HTML('</strong>'),
|
||||
line_break=HTML('<br>'),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -129,6 +129,22 @@ class CourseExpirationTestCase(ModuleStoreTestCase):
|
||||
content_availability_date = start_date
|
||||
self.assertEqual(result, content_availability_date + access_duration)
|
||||
|
||||
@mock.patch("openedx.features.course_duration_limits.access.get_course_run_details")
|
||||
def test_expired_upgrade_deadline(self, mock_get_course_run_details):
|
||||
"""
|
||||
The expiration date still exists if the upgrade deadline has passed
|
||||
"""
|
||||
access_duration = timedelta(weeks=7)
|
||||
mock_get_course_run_details.return_value = {'weeks_to_complete': 7}
|
||||
|
||||
start_date = now() - timedelta(weeks=10)
|
||||
course = CourseFactory(start=start_date)
|
||||
enrollment = CourseEnrollment.enroll(self.user, course.id, CourseMode.AUDIT)
|
||||
add_course_mode(course, upgrade_deadline_expired=True)
|
||||
result = get_user_course_expiration_date(self.user, course)
|
||||
content_availability_date = enrollment.created
|
||||
self.assertEqual(result, content_availability_date + access_duration)
|
||||
|
||||
@mock.patch("openedx.features.course_duration_limits.access.get_course_run_details")
|
||||
@ddt.data(
|
||||
({'user_partition_id': CONTENT_GATING_PARTITION_ID,
|
||||
|
||||
@@ -204,7 +204,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
|
||||
|
||||
# Fetch the view and verify the query counts
|
||||
# TODO: decrease query count as part of REVO-28
|
||||
with self.assertNumQueries(86, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with self.assertNumQueries(87, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with check_mongo_calls(4):
|
||||
url = course_home_url(self.course)
|
||||
self.client.get(url)
|
||||
@@ -538,6 +538,27 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
|
||||
)
|
||||
self.assertRedirects(response, expected_url)
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
|
||||
def test_expiration_banner_with_expired_upgrade_deadline(self):
|
||||
"""
|
||||
Ensure that a user accessing a course with an expired upgrade deadline
|
||||
will still see the course expiration banner without the upgrade related text.
|
||||
"""
|
||||
past = datetime(2010, 1, 1)
|
||||
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=past)
|
||||
course = CourseFactory.create(start=now() - timedelta(days=10))
|
||||
CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.AUDIT)
|
||||
CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.VERIFIED, expiration_datetime=past)
|
||||
user = UserFactory(password=self.TEST_PASSWORD)
|
||||
self.client.login(username=user.username, password=self.TEST_PASSWORD)
|
||||
CourseEnrollment.enroll(user, course.id, mode=CourseMode.AUDIT)
|
||||
|
||||
url = course_home_url(course)
|
||||
response = self.client.get(url)
|
||||
bannerText = get_expiration_banner_text(user, course)
|
||||
self.assertContains(response, bannerText, html=True)
|
||||
self.assertContains(response, TEST_BANNER_CLASS)
|
||||
|
||||
def test_audit_only_not_expired(self):
|
||||
"""
|
||||
Verify that enrolled users are NOT shown the course expiration banner and can
|
||||
|
||||
Reference in New Issue
Block a user