Merge pull request #24303 from edx/ddumesnil/due-dates-in-courseware-AA-44
AA-44: Adding due dates into courseware
This commit is contained in:
@@ -561,6 +561,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
|
||||
|
||||
context['show_bookmark_button'] = show_bookmark_button
|
||||
context['bookmarked'] = is_bookmarked
|
||||
context['format'] = getattr(self, 'format', '')
|
||||
|
||||
if render_items:
|
||||
rendered_item = item.render(view, context)
|
||||
|
||||
@@ -6,7 +6,9 @@ Tests for vertical module.
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
import pytz
|
||||
import six
|
||||
|
||||
import ddt
|
||||
@@ -67,6 +69,11 @@ class StubCompletionService(object):
|
||||
def blocks_to_mark_complete_on_view(self, blocks):
|
||||
return {} if self._completion_value == 1.0 else blocks
|
||||
|
||||
def vertical_is_complete(self, item):
|
||||
if item.scope_ids.block_type != 'vertical':
|
||||
raise ValueError('The passed in xblock is not a vertical type!')
|
||||
return self._completion_value
|
||||
|
||||
|
||||
class BaseVerticalBlockTest(XModuleXmlImportTest):
|
||||
"""
|
||||
@@ -120,18 +127,24 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
{'context': None, 'view': STUDENT_VIEW},
|
||||
{'context': {}, 'view': STUDENT_VIEW},
|
||||
{'context': {}, 'view': PUBLIC_VIEW},
|
||||
{'context': None, 'view': STUDENT_VIEW, 'completion_value': 0.0, 'days': 1},
|
||||
{'context': {}, 'view': STUDENT_VIEW, 'completion_value': 0.0, 'days': 1},
|
||||
{'context': {}, 'view': PUBLIC_VIEW, 'completion_value': 0.0, 'days': 1},
|
||||
{'context': {'format': 'Quiz'}, 'view': STUDENT_VIEW, 'completion_value': 1.0, 'days': 1}, # completed
|
||||
{'context': {'format': 'Exam'}, 'view': STUDENT_VIEW, 'completion_value': 0.0, 'days': 1}, # upcoming
|
||||
{'context': {'format': 'Homework'}, 'view': STUDENT_VIEW, 'completion_value': 0.0, 'days': -1}, # past due
|
||||
)
|
||||
def test_render_student_preview_view(self, context, view):
|
||||
def test_render_student_preview_view(self, context, view, completion_value, days):
|
||||
"""
|
||||
Test the rendering of the student and public view.
|
||||
"""
|
||||
self.module_system._services['bookmarks'] = Mock()
|
||||
now = datetime.now(pytz.UTC)
|
||||
self.vertical.due = now + timedelta(days=days)
|
||||
if view == STUDENT_VIEW:
|
||||
self.module_system._services['user'] = StubUserService()
|
||||
self.module_system._services['completion'] = StubCompletionService(enabled=True, completion_value=0.0)
|
||||
self.module_system._services['completion'] = StubCompletionService(enabled=True,
|
||||
completion_value=completion_value)
|
||||
elif view == PUBLIC_VIEW:
|
||||
self.module_system._services['user'] = StubUserService(is_anonymous=True)
|
||||
|
||||
@@ -140,10 +153,16 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
).content
|
||||
self.assertIn(self.test_html_1, html)
|
||||
self.assertIn(self.test_html_2, html)
|
||||
self.assertIn("'due': datetime.datetime({year}, {month}, {day}".format(
|
||||
year=self.vertical.due.year, month=self.vertical.due.month, day=self.vertical.due.day), html)
|
||||
if view == STUDENT_VIEW:
|
||||
self.assert_bookmark_info(self.assertIn, html)
|
||||
else:
|
||||
self.assert_bookmark_info(self.assertNotIn, html)
|
||||
if context:
|
||||
self.assertIn("'subsection_format': '{}'".format(context['format']), html)
|
||||
self.assertIn("'completed': {}".format(completion_value), html)
|
||||
self.assertIn("'past_due': {}".format(self.vertical.due < now), html)
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -163,7 +182,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
completion_value=completion_value,
|
||||
)
|
||||
self.module_system.render(self.vertical, STUDENT_VIEW, self.default_context)
|
||||
if (mark_completed_enabled):
|
||||
if mark_completed_enabled:
|
||||
self.assertEqual(
|
||||
mock_student_view.call_args[0][1]['wrap_xblock_data']['mark-completed-on-view-after-delay'], 9876
|
||||
)
|
||||
|
||||
@@ -5,8 +5,10 @@ VerticalBlock - an XBlock which renders its children in a column.
|
||||
|
||||
import logging
|
||||
from copy import copy
|
||||
from datetime import datetime
|
||||
from functools import reduce
|
||||
|
||||
import pytz
|
||||
import six
|
||||
from lxml import etree
|
||||
from web_fragments.fragment import Fragment
|
||||
@@ -89,10 +91,16 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
|
||||
'content': rendered_child.content
|
||||
})
|
||||
|
||||
completed = completion_service and completion_service.vertical_is_complete(self)
|
||||
past_due = not completed and self.due and self.due < datetime.now(pytz.UTC)
|
||||
fragment_context = {
|
||||
'items': contents,
|
||||
'xblock_context': context,
|
||||
'unit_title': self.display_name_with_default if not is_child_of_vertical else None,
|
||||
'due': self.due,
|
||||
'completed': completed,
|
||||
'past_due': past_due,
|
||||
'subsection_format': context.get('format', ''),
|
||||
}
|
||||
|
||||
if view == STUDENT_VIEW:
|
||||
|
||||
@@ -523,6 +523,33 @@ html.video-fullscreen {
|
||||
}
|
||||
}
|
||||
|
||||
.vert-due-date {
|
||||
color: #686b73;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
|
||||
.pill {
|
||||
font-size: 12px;
|
||||
|
||||
padding: 2px 8px;
|
||||
border-radius: 5px;
|
||||
margin-left: 8px;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
|
||||
&.completed {
|
||||
background-color: #f3f3f4;
|
||||
color: #2d323e;
|
||||
}
|
||||
|
||||
&.past-due {
|
||||
background-color: #d1d2d4;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vert-mod {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
<%page expression_filter="h"/>
|
||||
<%! from openedx.core.djangolib.markup import HTML %>
|
||||
|
||||
<%namespace name='static' file='/static_content.html'/>
|
||||
|
||||
<%!
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from openedx.core.djangolib.markup import HTML
|
||||
%>
|
||||
|
||||
%if unit_title and show_title:
|
||||
<h2 class="hd hd-2 unit-title">${unit_title}</h2>
|
||||
% endif
|
||||
|
||||
% if due:
|
||||
<%
|
||||
data_string = _("{subsection_format} due {{date}}").format(subsection_format=subsection_format)
|
||||
%>
|
||||
<div class="vert-due-date">
|
||||
<div class="localized-datetime" data-datetime="${due}" data-string="${data_string}" data-timezone="${user_timezone}"></div>
|
||||
% if completed:
|
||||
<div class="pill completed">${_('Completed')}</div>
|
||||
% elif past_due:
|
||||
<div class="pill past-due">${_('Past Due')}</div>
|
||||
%endif
|
||||
</div>
|
||||
% endif
|
||||
|
||||
% if show_bookmark_button:
|
||||
<%include file='bookmark_button.html' args="bookmark_id=bookmark_id, is_bookmarked=bookmarked"/>
|
||||
% endif
|
||||
@@ -18,3 +39,7 @@
|
||||
%endif
|
||||
% endfor
|
||||
</div>
|
||||
|
||||
<%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory">
|
||||
DateUtilFactory.transform('.localized-datetime');
|
||||
</%static:require_module_async>
|
||||
|
||||
Reference in New Issue
Block a user