Course Updates date validation

TNL-4115. Previously, course updates (which are intended to be posted with
dates, for sorting in the LMS) could be authored in studio with a valid
date, nothing, or a random string as the "date" for the update. As there
is no validation for this in studio, everything succeeded with no warning.

However, the LMS has problems parsing some of these values, and barfs when
loaded by learners.

The fix does two big things:
- gracefully handles invalid dates in LMS. These updates are now treated as
having a date of today, for sorting purposes.
- turns on validation in studio. Now, it is not only impossible to enter
invalid dates in studio, but notifications will draw the course author's
eye if any invalid updates were previously saved.

Test additions for this commit:

Adds:
- unit test for LMS parsing
- Jasmine test to confirm invalid dates cannot be set by the user
    -also adds event to setAndValidate instead of using a global object
- fix for lettuce test
    -It is no longer valid to enter the string "January 1, 2013" as this test
    had been doing. Keyed-in entries must use MM/DD/YY format.
This commit is contained in:
Eric Fischer
2016-03-25 16:16:48 -04:00
parent 05ffcb0ab8
commit 2735fdc2d4
9 changed files with 231 additions and 72 deletions

View File

@@ -439,7 +439,7 @@ class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
return self.data
else:
course_updates = [item for item in self.items if item.get('status') == self.STATUS_VISIBLE]
course_updates.sort(key=lambda item: datetime.strptime(item['date'], '%B %d, %Y'), reverse=True)
course_updates.sort(key=lambda item: CourseInfoModule.safe_parse_date(item['date']), reverse=True)
context = {
'visible_updates': course_updates[:3],
@@ -448,6 +448,16 @@ class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
return self.system.render_template("{0}/course_updates.html".format(self.TEMPLATE_DIR), context)
@staticmethod
def safe_parse_date(date):
"""
Since this is used solely for ordering purposes, use today's date as a default
"""
try:
return datetime.strptime(date, '%B %d, %Y')
except ValueError: # occurs for ill-formatted date values
return datetime.today()
@XBlock.tag("detached")
class CourseInfoDescriptor(CourseInfoFields, HtmlDescriptor):

View File

@@ -3,7 +3,7 @@ import unittest
from mock import Mock
from xblock.field_data import DictFieldData
from xmodule.html_module import HtmlModule, HtmlDescriptor
from xmodule.html_module import HtmlModule, HtmlDescriptor, CourseInfoModule
from . import get_test_system, get_test_descriptor_system
from opaque_keys.edx.locations import SlashSeparatedCourseKey
@@ -144,3 +144,40 @@ class HtmlDescriptorIndexingTestCase(unittest.TestCase):
"content": {"html_content": " This has HTML comment in it. HTML end. ", "display_name": "Text"},
"content_type": "Text"
})
class CourseInfoModuleTestCase(unittest.TestCase):
"""
Make sure that CourseInfoModule renders updates properly
"""
def test_updates_render(self):
"""
Tests that a course info module will render its updates, even if they are malformed.
"""
sample_update_data = [
{
"id": i,
"date": data,
"content": "This is a very important update!",
"status": CourseInfoModule.STATUS_VISIBLE,
} for i, data in enumerate(
[
'January 1, 1970',
'Marchtober 45, -1963',
'Welcome!',
'Date means "title", right?'
]
)
]
info_module = CourseInfoModule(
Mock(),
get_test_system(),
DictFieldData({'items': sample_update_data, 'data': ""}),
Mock()
)
# Prior to TNL-4115, an exception would be raised when trying to parse invalid dates in this method
try:
info_module.get_html()
except ValueError:
self.fail("CourseInfoModule could not parse an invalid date!")