diff --git a/cms/djangoapps/contentstore/tests/test_request_event.py b/cms/djangoapps/contentstore/tests/test_request_event.py index 7ac72f25a0..9c5bebe58d 100644 --- a/cms/djangoapps/contentstore/tests/test_request_event.py +++ b/cms/djangoapps/contentstore/tests/test_request_event.py @@ -3,7 +3,7 @@ from django.test import TestCase from django.urls import reverse -from six import unichr # pylint: disable=W0622 +from six import unichr from contentstore.views.helpers import event as cms_user_track @@ -20,7 +20,7 @@ class CMSLogTest(TestCase): """ requests = [ {"event": "my_event", "event_type": "my_event_type", "page": "my_page"}, - {"event": "{'json': 'object'}", "event_type": unichr(512), "page": "my_page"} # pylint: disable=unicode-format-string + {"event": "{'json': 'object'}", "event_type": unichr(512), "page": "my_page"} ] for request_params in requests: response = self.client.post(reverse(cms_user_track), request_params) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index bdeb662269..2163d7f151 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -15,6 +15,7 @@ from django.conf import settings from django.db.models import Prefetch from django.http import Http404, QueryDict from django.urls import reverse +from django.utils.translation import ugettext as _ from edx_django_utils.monitoring import function_trace from edx_when.api import get_dates_for_course from fs.errors import ResourceNotFound @@ -442,11 +443,12 @@ def get_course_assignment_due_dates(course, user, request, num_return=None, incl block_url = None now = datetime.now().replace(tzinfo=pytz.UTC) - assignment_released = item.start < now + assignment_released = item.start < now if item.start else None if assignment_released: block_url = reverse('jump_to', args=[course.id, block_key]) block_url = request.build_absolute_uri(block_url) if request else None - date_block.set_title(item.display_name, block_url) + assignment_title = item.display_name if item.display_name else _('Assignment') + date_block.set_title(assignment_title, block_url) date_blocks.append(date_block) date_blocks = sorted((b for b in date_blocks if b.is_enabled or include_past_dates), key=date_block_key_fn) diff --git a/lms/djangoapps/courseware/date_summary.py b/lms/djangoapps/courseware/date_summary.py index a431983b0c..d80a59da9a 100644 --- a/lms/djangoapps/courseware/date_summary.py +++ b/lms/djangoapps/courseware/date_summary.py @@ -62,6 +62,11 @@ class DateSummary(object): """The title of this summary.""" return '' + @property + def title_html(self): + """The title as html for this summary.""" + return '' + @property def description(self): """The detail text displayed by this summary.""" @@ -340,6 +345,7 @@ class CourseAssignmentDate(DateSummary): super().__init__(*args, **kwargs) self.assignment_date = None self.assignment_title = None + self.assignment_title_html = None @property def date(self): @@ -353,13 +359,17 @@ class CourseAssignmentDate(DateSummary): def title(self): return self.assignment_title + @property + def title_html(self): + return self.assignment_title_html + def set_title(self, title, link=None): + """ Used to set the title_html and title properties for the assignment date block """ if link: - self.assignment_title = HTML( + self.assignment_title_html = HTML( '{assignment_title}' ).format(assignment_link=link, assignment_title=title) - else: - self.assignment_title = title + self.assignment_title = title class CourseExpiredDate(DateSummary): diff --git a/lms/djangoapps/courseware/tests/test_date_summary.py b/lms/djangoapps/courseware/tests/test_date_summary.py index 49908e8697..82f33a1c69 100644 --- a/lms/djangoapps/courseware/tests/test_date_summary.py +++ b/lms/djangoapps/courseware/tests/test_date_summary.py @@ -132,7 +132,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) self.assert_block_types(course, user, expected_blocks) - def test_enabled_block_types_with_assignments(self): + def test_enabled_block_types_with_assignments(self): # pylint: disable=too-many-statements """ Creates a course with multiple subsections to test all of the different cases for assignment dates showing up. Mocks out calling the edx-when @@ -187,6 +187,24 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): due=now - timedelta(days=7), graded=False, ) + subsection_6 = ItemFactory.create( + category='sequential', + display_name='No start date', + parent_location=section.location, + start=None, + due=now + timedelta(days=9), + graded=True, + ) + subsection_7 = ItemFactory.create( + category='sequential', + # Setting display name to None should set the assignment title to 'Assignment' + display_name=None, + parent_location=section.location, + start=now - timedelta(days=14), + due=now + timedelta(days=10), + graded=True, + ) + dummy_subsection = ItemFactory.create(category='sequential') with patch('lms.djangoapps.courseware.courses.get_dates_for_course') as mock_get_dates: mock_get_dates.return_value = { @@ -200,6 +218,12 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): (subsection_4.location, 'start'): subsection_4.start, (subsection_5.location, 'due'): subsection_5.due, (subsection_5.location, 'start'): subsection_5.start, + (subsection_6.location, 'due'): subsection_6.due, + (subsection_7.location, 'due'): subsection_7.due, + (subsection_7.location, 'start'): subsection_7.start, + # Adding this in for the case where we return a block that + # doesn't actually exist as part of the course. Should just be ignored. + (dummy_subsection.location, 'due'): dummy_subsection.due, } # Standard widget case where we restrict the number of assignments. expected_blocks = ( @@ -210,7 +234,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): self.assertEqual(set(type(b) for b in blocks), set(expected_blocks)) assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks) for assignment in assignment_blocks: - assignment_title = str(assignment.title) + assignment_title = str(assignment.title_html) or str(assignment.title) self.assertNotEqual(assignment_title, 'Third nearest assignment') self.assertNotEqual(assignment_title, 'Past due date') self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections') @@ -226,14 +250,15 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): # No restrictions on number of assignments to return expected_blocks = ( CourseStartDate, TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate, - CourseAssignmentDate, CourseEndDate, VerificationDeadlineDate + CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate, + VerificationDeadlineDate ) blocks = get_course_date_blocks(course, user, request, include_past_dates=True) self.assertEqual(len(blocks), len(expected_blocks)) self.assertEqual(set(type(b) for b in blocks), set(expected_blocks)) assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks) for assignment in assignment_blocks: - assignment_title = str(assignment.title) + assignment_title = str(assignment.title_html) or str(assignment.title) self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections') # checking if it is _in_ the title instead of being the title since released assignments # are actually links. Unreleased assignments are just the string of the title. @@ -251,6 +276,15 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): self.assertGreater(now, assignment.date) for html_tag in assignment_title_html: self.assertIn(html_tag, assignment_title) + elif 'No start date' == assignment_title: + # Can't determine if it is released so it does not get a link + for html_tag in assignment_title_html: + self.assertNotIn(html_tag, assignment_title) + # This is the item with no display name where we set one ourselves. + elif 'Assignment' in assignment_title: + # Can't determine if it is released so it does not get a link + for html_tag in assignment_title_html: + self.assertIn(html_tag, assignment_title) def test_enabled_block_types_with_expired_course(self): course = create_course_run(days_till_start=-100) diff --git a/openedx/features/course_experience/templates/course_experience/dates-summary.html b/openedx/features/course_experience/templates/course_experience/dates-summary.html index e8a66c083b..0cfa204bcc 100644 --- a/openedx/features/course_experience/templates/course_experience/dates-summary.html +++ b/openedx/features/course_experience/templates/course_experience/dates-summary.html @@ -10,7 +10,9 @@ from django.utils.translation import ugettext as _ % if course_date.date:
% endif - % if course_date.title: + % if course_date.title_html: +