Merge pull request #19293 from edx/bfiller/REVE-96

Don't allow audit-only courses to expire
This commit is contained in:
Bill Filler
2018-11-26 15:49:02 -05:00
committed by GitHub
7 changed files with 57 additions and 7 deletions

View File

@@ -9,6 +9,7 @@ from django.apps import apps
from django.utils import timezone
from django.utils.translation import ugettext as _
from course_modes.models import CourseMode
from util.date_utils import DEFAULT_SHORT_DATE_FORMAT, strftime_localized
from lms.djangoapps.courseware.access_response import AccessError
from lms.djangoapps.courseware.access_utils import ACCESS_GRANTED
@@ -60,6 +61,9 @@ def get_user_course_expiration_date(user, course):
access_duration = MIN_DURATION
if not CourseMode.verified_mode_for_course(course.id):
return None
CourseEnrollment = apps.get_model('student.CourseEnrollment')
enrollment = CourseEnrollment.get_enrollment(user, course.id)
if enrollment is None or enrollment.mode != 'audit':

View File

@@ -9,6 +9,7 @@ import mock
from course_modes.models import CourseMode
from openedx.features.course_duration_limits.access import get_user_course_expiration_date, MIN_DURATION, MAX_DURATION
from openedx.features.course_experience.tests.views.helpers import add_course_mode
from student.models import CourseEnrollment
from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
@@ -25,6 +26,9 @@ class CourseExpirationTestCase(ModuleStoreTestCase):
)
self.user = UserFactory()
# Make this a verified course so we can test expiration date
add_course_mode(self.course, upgrade_deadline_expired=False)
def tearDown(self):
CourseEnrollment.unenroll(self.user, self.course.id)
super(CourseExpirationTestCase, self).tearDown()
@@ -79,6 +83,10 @@ class CourseExpirationTestCase(ModuleStoreTestCase):
past_course = CourseFactory(start=start_date)
enrollment = CourseEnrollment.enroll(self.user, past_course.id, CourseMode.AUDIT)
result = get_user_course_expiration_date(self.user, past_course)
self.assertEqual(result, None)
add_course_mode(past_course, upgrade_deadline_expired=False)
result = get_user_course_expiration_date(self.user, past_course)
content_availability_date = enrollment.created
self.assertEqual(result, content_availability_date + access_duration)
@@ -87,5 +95,9 @@ class CourseExpirationTestCase(ModuleStoreTestCase):
future_course = CourseFactory(start=start_date)
enrollment = CourseEnrollment.enroll(self.user, future_course.id, CourseMode.AUDIT)
result = get_user_course_expiration_date(self.user, future_course)
self.assertEqual(result, None)
add_course_mode(future_course, upgrade_deadline_expired=False)
result = get_user_course_expiration_date(self.user, future_course)
content_availability_date = start_date
self.assertEqual(result, content_availability_date + access_duration)

View File

@@ -45,6 +45,9 @@ from .test_course_updates import create_course_update, remove_course_updates
TEST_PASSWORD = 'test'
TEST_CHAPTER_NAME = 'Test Chapter'
TEST_COURSE_TOOLS = 'Course Tools'
TEST_COURSE_TODAY = 'Today is'
TEST_BANNER_CLASS = '<div class="page-banner">'
TEST_WELCOME_MESSAGE = '<h2>Welcome!</h2>'
TEST_UPDATE_MESSAGE = '<h2>Test Update!</h2>'
TEST_COURSE_UPDATES_TOOL = '/course/updates">'
@@ -183,7 +186,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
course_home_url(self.course)
# Fetch the view and verify the query counts
with self.assertNumQueries(84, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with self.assertNumQueries(68, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with check_mongo_calls(4):
url = course_home_url(self.course)
self.client.get(url)
@@ -241,8 +244,8 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
response = self.client.get(url)
# Verify that the course tools and dates are always shown
self.assertContains(response, 'Course Tools')
self.assertContains(response, 'Today is')
self.assertContains(response, TEST_COURSE_TOOLS)
self.assertContains(response, TEST_COURSE_TODAY)
# Verify that the outline, start button, course sock, and welcome message
# are only shown to enrolled users.
@@ -279,8 +282,8 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
response = self.client.get(url)
# Verify that the course tools and dates are always shown
self.assertContains(response, 'Course Tools')
self.assertContains(response, 'Today is')
self.assertContains(response, TEST_COURSE_TOOLS)
self.assertContains(response, TEST_COURSE_TODAY)
# Verify that welcome messages are never shown
self.assertNotContains(response, TEST_WELCOME_MESSAGE)
@@ -393,7 +396,6 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
the student dashboard, not a 404.
"""
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=date(2010, 1, 1))
course = CourseFactory.create(start=THREE_YEARS_AGO)
url = course_home_url(course)
@@ -421,6 +423,20 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
)
self.assertRedirects(response, expected_url)
def test_audit_only_not_expired(self):
"""
Verify that enrolled users are NOT shown the course expiration banner and can
access the course home page if course audit only
"""
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=date(2010, 1, 1))
audit_only_course = CourseFactory.create()
self.create_user_for_course(audit_only_course, CourseUserType.ENROLLED)
response = self.client.get(course_home_url(audit_only_course))
self.assertEqual(response.status_code, 200)
self.assertContains(response, TEST_COURSE_TOOLS)
self.assertContains(response, TEST_COURSE_TODAY)
self.assertNotContains(response, TEST_BANNER_CLASS)
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
@mock.patch("util.date_utils.strftime_localized")
def test_non_live_course_other_language(self, mock_strftime_localized):
@@ -505,6 +521,7 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
response = self.client.get(url)
bannerText = get_expiration_banner_text(user, self.course)
self.assertContains(response, bannerText, html=True)
self.assertContains(response, TEST_BANNER_CLASS)
# Verify that enrolled users are not shown the course expiration banner if content gating is disabled
config.enabled = False