Commit e12a704c by Diana Huang Committed by Andy Armstrong

Add new course dates fragment.

Also add it to the course home page.
parent 97c08451
...@@ -527,19 +527,19 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest ...@@ -527,19 +527,19 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest
self.assertNotContains(response, "Schools & Partners") self.assertNotContains(response, "Schools & Partners")
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@freezegun.freeze_time('2015-01-02')
def test_course_closed(self): def test_course_closed(self):
for mode in ["honor", "verified"]: with freezegun.freeze_time('2015-01-02'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) for mode in ["honor", "verified"]:
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
self.course.enrollment_end = datetime(2015, 01, 01) self.course.enrollment_end = datetime(2015, 01, 01)
modulestore().update_item(self.course, self.user.id) modulestore().update_item(self.course, self.user.id)
url = reverse('course_modes_choose', args=[unicode(self.course.id)]) url = reverse('course_modes_choose', args=[unicode(self.course.id)])
response = self.client.get(url) response = self.client.get(url)
# URL-encoded version of 1/1/15, 12:00 AM # URL-encoded version of 1/1/15, 12:00 AM
redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM' redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM'
self.assertRedirects(response, redirect_url) self.assertRedirects(response, redirect_url)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
......
...@@ -31,7 +31,6 @@ class InMemoryBackend(object): ...@@ -31,7 +31,6 @@ class InMemoryBackend(object):
self.events.append(event) self.events.append(event)
@freeze_time(FROZEN_TIME)
@override_settings( @override_settings(
EVENT_TRACKING_BACKENDS=IN_MEMORY_BACKEND_CONFIG EVENT_TRACKING_BACKENDS=IN_MEMORY_BACKEND_CONFIG
) )
...@@ -46,6 +45,10 @@ class EventTrackingTestCase(TestCase): ...@@ -46,6 +45,10 @@ class EventTrackingTestCase(TestCase):
# Make this more robust to the addition of new events that the test doesn't care about. # Make this more robust to the addition of new events that the test doesn't care about.
def setUp(self): def setUp(self):
freezer = freeze_time(FROZEN_TIME)
freezer.start()
self.addCleanup(freezer.stop)
super(EventTrackingTestCase, self).setUp() super(EventTrackingTestCase, self).setUp()
self.recreate_tracker() self.recreate_tracker()
......
...@@ -107,7 +107,7 @@ def server_track(request, event_type, event, page=None): ...@@ -107,7 +107,7 @@ def server_track(request, event_type, event, page=None):
"event": event, "event": event,
"agent": _get_request_header(request, 'HTTP_USER_AGENT').decode('latin1'), "agent": _get_request_header(request, 'HTTP_USER_AGENT').decode('latin1'),
"page": page, "page": page,
"time": datetime.datetime.utcnow(), "time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
"host": _get_request_header(request, 'SERVER_NAME'), "host": _get_request_header(request, 'SERVER_NAME'),
"context": eventtracker.get_tracker().resolve_context(), "context": eventtracker.get_tracker().resolve_context(),
} }
...@@ -155,7 +155,7 @@ def task_track(request_info, task_info, event_type, event, page=None): ...@@ -155,7 +155,7 @@ def task_track(request_info, task_info, event_type, event, page=None):
"event": full_event, "event": full_event,
"agent": request_info.get('agent', 'unknown'), "agent": request_info.get('agent', 'unknown'),
"page": page, "page": page,
"time": datetime.datetime.utcnow(), "time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
"host": request_info.get('host', 'unknown'), "host": request_info.get('host', 'unknown'),
"context": eventtracker.get_tracker().resolve_context(), "context": eventtracker.get_tracker().resolve_context(),
} }
......
...@@ -139,42 +139,42 @@ class SequenceBlockTestCase(XModuleXmlImportTest): ...@@ -139,42 +139,42 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
self.assertIn("seq_module.html", html) self.assertIn("seq_module.html", html)
self.assertIn("'banner_text': None", html) self.assertIn("'banner_text': None", html)
@freeze_time(COURSE_END_DATE)
def test_hidden_content_past_due(self): def test_hidden_content_past_due(self):
progress_url = 'http://test_progress_link' with freeze_time(COURSE_END_DATE):
html = self._get_rendered_student_view( progress_url = 'http://test_progress_link'
self.sequence_4_1, html = self._get_rendered_student_view(
extra_context=dict(progress_url=progress_url), self.sequence_4_1,
) extra_context=dict(progress_url=progress_url),
self.assertIn("hidden_content.html", html) )
self.assertIn(progress_url, html) self.assertIn("hidden_content.html", html)
self.assertIn(progress_url, html)
@freeze_time(COURSE_END_DATE)
def test_masquerade_hidden_content_past_due(self): def test_masquerade_hidden_content_past_due(self):
html = self._get_rendered_student_view( with freeze_time(COURSE_END_DATE):
self.sequence_4_1, html = self._get_rendered_student_view(
extra_context=dict(specific_masquerade=True), self.sequence_4_1,
) extra_context=dict(specific_masquerade=True),
self.assertIn("seq_module.html", html) )
self.assertIn( self.assertIn("seq_module.html", html)
"'banner_text': 'Because the due date has passed, " self.assertIn(
"this assignment is hidden from the learner.'", "'banner_text': 'Because the due date has passed, "
html "this assignment is hidden from the learner.'",
) html
)
@freeze_time(PAST_DUE_BEFORE_END_DATE)
def test_hidden_content_self_paced_past_due_before_end(self): def test_hidden_content_self_paced_past_due_before_end(self):
html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True) with freeze_time(PAST_DUE_BEFORE_END_DATE):
self.assertIn("seq_module.html", html) html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True)
self.assertIn("'banner_text': None", html) self.assertIn("seq_module.html", html)
self.assertIn("'banner_text': None", html)
@freeze_time(COURSE_END_DATE + timedelta(days=7))
def test_hidden_content_self_paced_past_end(self): def test_hidden_content_self_paced_past_end(self):
progress_url = 'http://test_progress_link' with freeze_time(COURSE_END_DATE + timedelta(days=7)):
html = self._get_rendered_student_view( progress_url = 'http://test_progress_link'
self.sequence_4_1, html = self._get_rendered_student_view(
extra_context=dict(progress_url=progress_url), self.sequence_4_1,
self_paced=True, extra_context=dict(progress_url=progress_url),
) self_paced=True,
self.assertIn("hidden_content.html", html) )
self.assertIn(progress_url, html) self.assertIn("hidden_content.html", html)
self.assertIn(progress_url, html)
...@@ -35,8 +35,11 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase): ...@@ -35,8 +35,11 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
display_name='Verified Course' display_name='Verified Course'
) )
@freeze_time(now)
def setUp(self): def setUp(self):
freezer = freeze_time(self.now)
freezer.start()
self.addCleanup(freezer.stop)
super(CertificatesRestApiTest, self).setUp() super(CertificatesRestApiTest, self).setUp()
self.student = UserFactory.create(password=USER_PASSWORD) self.student = UserFactory.create(password=USER_PASSWORD)
......
...@@ -326,8 +326,10 @@ class CertificateGetTests(SharedModuleStoreTestCase): ...@@ -326,8 +326,10 @@ class CertificateGetTests(SharedModuleStoreTestCase):
now = timezone.now() now = timezone.now()
@classmethod @classmethod
@freeze_time(now)
def setUpClass(cls): def setUpClass(cls):
cls.freezer = freeze_time(cls.now)
cls.freezer.start()
super(CertificateGetTests, cls).setUpClass() super(CertificateGetTests, cls).setUpClass()
cls.student = UserFactory() cls.student = UserFactory()
cls.student_no_cert = UserFactory() cls.student_no_cert = UserFactory()
...@@ -365,6 +367,10 @@ class CertificateGetTests(SharedModuleStoreTestCase): ...@@ -365,6 +367,10 @@ class CertificateGetTests(SharedModuleStoreTestCase):
verify_uuid=cls.uuid, verify_uuid=cls.uuid,
) )
@classmethod
def tearDownClass(cls):
cls.freezer.stop()
def test_get_certificate_for_user(self): def test_get_certificate_for_user(self):
""" """
Test to get a certificate for a user for a specific course. Test to get a certificate for a user for a specific course.
......
...@@ -33,39 +33,38 @@ class EdxRestApiClientTest(TestCase): ...@@ -33,39 +33,38 @@ class EdxRestApiClientTest(TestCase):
self.user = UserFactory() self.user = UserFactory()
@httpretty.activate @httpretty.activate
@freeze_time('2015-7-2')
def test_tracking_context(self): def test_tracking_context(self):
""" """
Ensure the tracking context is set up in the api client correctly and Ensure the tracking context is set up in the api client correctly and
automatically. automatically.
""" """
with freeze_time('2015-7-2'):
# fake an E-Commerce API request.
httpretty.register_uri(
httpretty.POST,
'{}/baskets/1/'.format(settings.ECOMMERCE_API_URL.strip('/')),
status=200, body='{}',
adding_headers={'Content-Type': JSON}
)
# fake an E-Commerce API request. mock_tracker = mock.Mock()
httpretty.register_uri( mock_tracker.resolve_context = mock.Mock(return_value={'client_id': self.TEST_CLIENT_ID, 'ip': '127.0.0.1'})
httpretty.POST, with mock.patch('openedx.core.djangoapps.commerce.utils.tracker.get_tracker', return_value=mock_tracker):
'{}/baskets/1/'.format(settings.ECOMMERCE_API_URL.strip('/')), ecommerce_api_client(self.user).baskets(1).post()
status=200, body='{}',
adding_headers={'Content-Type': JSON}
)
mock_tracker = mock.Mock()
mock_tracker.resolve_context = mock.Mock(return_value={'client_id': self.TEST_CLIENT_ID, 'ip': '127.0.0.1'})
with mock.patch('openedx.core.djangoapps.commerce.utils.tracker.get_tracker', return_value=mock_tracker):
ecommerce_api_client(self.user).baskets(1).post()
# Verify the JWT includes the tracking context for the user # Verify the JWT includes the tracking context for the user
actual_header = httpretty.last_request().headers['Authorization'] actual_header = httpretty.last_request().headers['Authorization']
claims = { claims = {
'tracking_context': { 'tracking_context': {
'lms_user_id': self.user.id, # pylint: disable=no-member 'lms_user_id': self.user.id, # pylint: disable=no-member
'lms_client_id': self.TEST_CLIENT_ID, 'lms_client_id': self.TEST_CLIENT_ID,
'lms_ip': '127.0.0.1', 'lms_ip': '127.0.0.1',
}
} }
} expected_jwt = JwtBuilder(self.user).build_token(['email', 'profile'], additional_claims=claims)
expected_jwt = JwtBuilder(self.user).build_token(['email', 'profile'], additional_claims=claims) expected_header = 'JWT {}'.format(expected_jwt)
expected_header = 'JWT {}'.format(expected_jwt) self.assertEqual(actual_header, expected_header)
self.assertEqual(actual_header, expected_header)
@httpretty.activate @httpretty.activate
def test_client_unicode(self): def test_client_unicode(self):
......
...@@ -7,6 +7,8 @@ from django.core.urlresolvers import reverse ...@@ -7,6 +7,8 @@ from django.core.urlresolvers import reverse
from freezegun import freeze_time from freezegun import freeze_time
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from pytz import utc from pytz import utc
from waffle.testutils import override_flag
from openedx.features.course_experience import UNIFIED_COURSE_EXPERIENCE_FLAG
from commerce.models import CommerceConfiguration from commerce.models import CommerceConfiguration
from course_modes.tests.factories import CourseModeFactory from course_modes.tests.factories import CourseModeFactory
...@@ -169,56 +171,66 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -169,56 +171,66 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.setup_course_and_user(**course_options) self.setup_course_and_user(**course_options)
self.assert_block_types(expected_blocks) self.assert_block_types(expected_blocks)
@freeze_time('2015-01-02')
def test_todays_date_block(self): def test_todays_date_block(self):
""" """
Helper function to test that today's date block renders correctly Helper function to test that today's date block renders correctly
and displays the correct time, accounting for daylight savings and displays the correct time, accounting for daylight savings
""" """
self.setup_course_and_user() with freeze_time('2015-01-02'):
block = TodaysDate(self.course, self.user) self.setup_course_and_user()
self.assertTrue(block.is_enabled) block = TodaysDate(self.course, self.user)
self.assertEqual(block.date, datetime.now(utc)) self.assertTrue(block.is_enabled)
self.assertEqual(block.title, 'current_datetime') self.assertEqual(block.date, datetime.now(utc))
self.assertEqual(block.title, 'current_datetime')
@freeze_time('2015-01-02')
def test_todays_date_no_timezone(self):
self.setup_course_and_user()
self.client.login(username='mrrobot', password='test')
html_elements = [ @ddt.data(
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>', 'info',
'<div class="date-summary-container">', 'openedx.course_experience.course_home',
'<div class="date-summary date-summary-todays-date">', )
'<span class="hd hd-4 heading localized-datetime"', @override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
'data-datetime="2015-01-02 00:00:00+00:00"', def test_todays_date_no_timezone(self, url_name):
'data-string="Today is {date}"', with freeze_time('2015-01-02'):
'data-timezone="None"' self.setup_course_and_user()
] self.client.login(username='mrrobot', password='test')
url = reverse('info', args=(self.course.id, ))
response = self.client.get(url) html_elements = [
for html in html_elements: '<h3 class="hd hd-6 handouts-header">Important Course Dates</h3>',
self.assertContains(response, html) '<div class="date-summary-container">',
'<div class="date-summary date-summary-todays-date">',
@freeze_time('2015-01-02') '<span class="hd hd-6 heading localized-datetime"',
def test_todays_date_timezone(self): 'data-datetime="2015-01-02 00:00:00+00:00"',
self.setup_course_and_user() 'data-string="Today is {date}"',
self.client.login(username='mrrobot', password='test') 'data-timezone="None"'
set_user_preference(self.user, "time_zone", "America/Los_Angeles") ]
url = reverse('info', args=(self.course.id,)) url = reverse(url_name, args=(self.course.id, ))
response = self.client.get(url) response = self.client.get(url, follow=True)
for html in html_elements:
self.assertContains(response, html)
html_elements = [ @ddt.data(
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>', 'info',
'<div class="date-summary-container">', 'openedx.course_experience.course_home',
'<div class="date-summary date-summary-todays-date">', )
'<span class="hd hd-4 heading localized-datetime"', @override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
'data-datetime="2015-01-02 00:00:00+00:00"', def test_todays_date_timezone(self, url_name):
'data-string="Today is {date}"', with freeze_time('2015-01-02'):
'data-timezone="America/Los_Angeles"' self.setup_course_and_user()
] self.client.login(username='mrrobot', password='test')
for html in html_elements: set_user_preference(self.user, "time_zone", "America/Los_Angeles")
self.assertContains(response, html) url = reverse(url_name, args=(self.course.id,))
response = self.client.get(url, follow=True)
html_elements = [
'<h3 class="hd hd-6 handouts-header">Important Course Dates</h3>',
'<div class="date-summary-container">',
'<div class="date-summary date-summary-todays-date">',
'<span class="hd hd-6 heading localized-datetime"',
'data-datetime="2015-01-02 00:00:00+00:00"',
'data-string="Today is {date}"',
'data-timezone="America/Los_Angeles"'
]
for html in html_elements:
self.assertContains(response, html)
## Tests Course Start Date ## Tests Course Start Date
def test_course_start_date(self): def test_course_start_date(self):
...@@ -226,33 +238,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -226,33 +238,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
block = CourseStartDate(self.course, self.user) block = CourseStartDate(self.course, self.user)
self.assertEqual(block.date, self.course.start) self.assertEqual(block.date, self.course.start)
@freeze_time('2015-01-02') @ddt.data(
def test_start_date_render(self): 'info',
self.setup_course_and_user() 'openedx.course_experience.course_home',
self.client.login(username='mrrobot', password='test') )
url = reverse('info', args=(self.course.id,)) @override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
response = self.client.get(url) def test_start_date_render(self, url_name):
html_elements = [ with freeze_time('2015-01-02'):
'data-string="in 1 day - {date}"', self.setup_course_and_user()
'data-datetime="2015-01-03 00:00:00+00:00"' self.client.login(username='mrrobot', password='test')
] url = reverse(url_name, args=(self.course.id,))
for html in html_elements: response = self.client.get(url, follow=True)
self.assertContains(response, html) html_elements = [
'data-string="in 1 day - {date}"',
@freeze_time('2015-01-02') 'data-datetime="2015-01-03 00:00:00+00:00"'
def test_start_date_render_time_zone(self): ]
self.setup_course_and_user() for html in html_elements:
self.client.login(username='mrrobot', password='test') self.assertContains(response, html)
set_user_preference(self.user, "time_zone", "America/Los_Angeles")
url = reverse('info', args=(self.course.id,)) @ddt.data(
response = self.client.get(url) 'info',
html_elements = [ 'openedx.course_experience.course_home',
'data-string="in 1 day - {date}"', )
'data-datetime="2015-01-03 00:00:00+00:00"', @override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
'data-timezone="America/Los_Angeles"' def test_start_date_render_time_zone(self, url_name):
] with freeze_time('2015-01-02'):
for html in html_elements: self.setup_course_and_user()
self.assertContains(response, html) self.client.login(username='mrrobot', password='test')
set_user_preference(self.user, "time_zone", "America/Los_Angeles")
url = reverse(url_name, args=(self.course.id,))
response = self.client.get(url, follow=True)
html_elements = [
'data-string="in 1 day - {date}"',
'data-datetime="2015-01-03 00:00:00+00:00"',
'data-timezone="America/Los_Angeles"'
]
for html in html_elements:
self.assertContains(response, html)
## Tests Course End Date Block ## Tests Course End Date Block
def test_course_end_date_for_certificate_eligible_mode(self): def test_course_end_date_for_certificate_eligible_mode(self):
...@@ -308,15 +330,15 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -308,15 +330,15 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
if expected_cookie_value is not None: if expected_cookie_value is not None:
self.assertIn(str(expected_cookie_value), self.client.cookies[upgrade_cookie_name].value) self.assertIn(str(expected_cookie_value), self.client.cookies[upgrade_cookie_name].value)
@freeze_time('2015-01-02')
def test_verified_upgrade_deadline_date(self): def test_verified_upgrade_deadline_date(self):
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT) with freeze_time('2015-01-02'):
self.client.login(username='mrrobot', password='test') self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
block = VerifiedUpgradeDeadlineDate(self.course, self.user) self.client.login(username='mrrobot', password='test')
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=1)) block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.assertTrue(block.is_enabled) self.assertEqual(block.date, datetime.now(utc) + timedelta(days=1))
self.assertEqual(block.link, reverse('verify_student_upgrade_and_verify', args=(self.course.id,))) self.assertTrue(block.is_enabled)
self.check_upgrade_banner() self.assertEqual(block.link, reverse('verify_student_upgrade_and_verify', args=(self.course.id,)))
self.check_upgrade_banner()
def test_without_upgrade_deadline(self): def test_without_upgrade_deadline(self):
self.setup_course_and_user(enrollment_mode=None) self.setup_course_and_user(enrollment_mode=None)
...@@ -326,43 +348,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -326,43 +348,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertIsNone(block.date) self.assertIsNone(block.date)
self.check_upgrade_banner(banner_expected=False) self.check_upgrade_banner(banner_expected=False)
@freeze_time('2015-01-02')
def test_verified_upgrade_banner_not_present_past_deadline(self): def test_verified_upgrade_banner_not_present_past_deadline(self):
self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT) with freeze_time('2015-01-02'):
self.client.login(username='mrrobot', password='test') self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT)
block = VerifiedUpgradeDeadlineDate(self.course, self.user) self.client.login(username='mrrobot', password='test')
self.assertFalse(block.is_enabled) block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.check_upgrade_banner(banner_expected=False) self.assertFalse(block.is_enabled)
self.check_upgrade_banner(banner_expected=False)
@freeze_time('2015-01-02')
def test_verified_upgrade_banner_cookie(self): def test_verified_upgrade_banner_cookie(self):
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT) with freeze_time('2015-01-02'):
self.client.login(username='mrrobot', password='test') self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test')
# No URL parameter or cookie present, notification should not be shown. # No URL parameter or cookie present, notification should not be shown.
self.check_upgrade_banner(include_url_parameter=False, banner_expected=False) self.check_upgrade_banner(include_url_parameter=False, banner_expected=False)
# Now pass URL parameter-- notification should be shown. # Now pass URL parameter-- notification should be shown.
self.check_upgrade_banner(include_url_parameter=True) self.check_upgrade_banner(include_url_parameter=True)
# A cookie should be set in the previous call, so it is no longer necessary to pass # A cookie should be set in the previous call, so it is no longer necessary to pass
# the URL parameter in order to see the notification. # the URL parameter in order to see the notification.
self.check_upgrade_banner(include_url_parameter=False) self.check_upgrade_banner(include_url_parameter=False)
# Store the current course_id for testing # Store the current course_id for testing
old_course_id = self.course.id old_course_id = self.course.id
# Change to another course # Change to another course
self.setup_course_and_user(days_till_upgrade_deadline=1, self.setup_course_and_user(days_till_upgrade_deadline=1,
user_enrollment_mode=CourseMode.AUDIT, user_enrollment_mode=CourseMode.AUDIT,
create_user=False) create_user=False)
# Banner should not be present in the newly created course # Banner should not be present in the newly created course
self.check_upgrade_banner(include_url_parameter=False, self.check_upgrade_banner(include_url_parameter=False,
banner_expected=False, banner_expected=False,
expected_cookie_value=old_course_id) expected_cookie_value=old_course_id)
# Unfortunately (according to django doc), it is not possible to test expiration of the cookie. # Unfortunately (according to django doc), it is not possible to test expiration of the cookie.
def test_ecommerce_checkout_redirect(self): def test_ecommerce_checkout_redirect(self):
"""Verify the block link redirects to ecommerce checkout if it's enabled.""" """Verify the block link redirects to ecommerce checkout if it's enabled."""
...@@ -387,63 +409,63 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -387,63 +409,63 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
block = VerificationDeadlineDate(self.course, self.user) block = VerificationDeadlineDate(self.course, self.user)
self.assertFalse(block.is_enabled) self.assertFalse(block.is_enabled)
@freeze_time('2015-01-02')
def test_verification_deadline_date_upcoming(self): def test_verification_deadline_date_upcoming(self):
self.setup_course_and_user(days_till_start=-1) with freeze_time('2015-01-02'):
block = VerificationDeadlineDate(self.course, self.user) self.setup_course_and_user(days_till_start=-1)
self.assertEqual(block.css_class, 'verification-deadline-upcoming') block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.title, 'Verification Deadline') self.assertEqual(block.css_class, 'verification-deadline-upcoming')
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14)) self.assertEqual(block.title, 'Verification Deadline')
self.assertEqual( self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
block.description, self.assertEqual(
'You must successfully complete verification before this date to qualify for a Verified Certificate.' block.description,
) 'You must successfully complete verification before this date to qualify for a Verified Certificate.'
self.assertEqual(block.link_text, 'Verify My Identity') )
self.assertEqual(block.link, reverse('verify_student_verify_now', args=(self.course.id,))) self.assertEqual(block.link_text, 'Verify My Identity')
self.assertEqual(block.link, reverse('verify_student_verify_now', args=(self.course.id,)))
@freeze_time('2015-01-02')
def test_verification_deadline_date_retry(self): def test_verification_deadline_date_retry(self):
self.setup_course_and_user(days_till_start=-1, verification_status='denied') with freeze_time('2015-01-02'):
block = VerificationDeadlineDate(self.course, self.user) self.setup_course_and_user(days_till_start=-1, verification_status='denied')
self.assertEqual(block.css_class, 'verification-deadline-retry') block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.title, 'Verification Deadline') self.assertEqual(block.css_class, 'verification-deadline-retry')
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14)) self.assertEqual(block.title, 'Verification Deadline')
self.assertEqual( self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
block.description, self.assertEqual(
'You must successfully complete verification before this date to qualify for a Verified Certificate.' block.description,
) 'You must successfully complete verification before this date to qualify for a Verified Certificate.'
self.assertEqual(block.link_text, 'Retry Verification') )
self.assertEqual(block.link, reverse('verify_student_reverify')) self.assertEqual(block.link_text, 'Retry Verification')
self.assertEqual(block.link, reverse('verify_student_reverify'))
@freeze_time('2015-01-02')
def test_verification_deadline_date_denied(self): def test_verification_deadline_date_denied(self):
self.setup_course_and_user( with freeze_time('2015-01-02'):
days_till_start=-10, self.setup_course_and_user(
verification_status='denied', days_till_start=-10,
days_till_verification_deadline=-1, verification_status='denied',
) days_till_verification_deadline=-1,
block = VerificationDeadlineDate(self.course, self.user) )
self.assertEqual(block.css_class, 'verification-deadline-passed') block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.title, 'Missed Verification Deadline') self.assertEqual(block.css_class, 'verification-deadline-passed')
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=-1)) self.assertEqual(block.title, 'Missed Verification Deadline')
self.assertEqual( self.assertEqual(block.date, datetime.now(utc) + timedelta(days=-1))
block.description, self.assertEqual(
"Unfortunately you missed this course's deadline for a successful verification." block.description,
) "Unfortunately you missed this course's deadline for a successful verification."
self.assertEqual(block.link_text, 'Learn More') )
self.assertEqual(block.link, '') self.assertEqual(block.link_text, 'Learn More')
self.assertEqual(block.link, '')
@freeze_time('2015-01-02')
@ddt.data( @ddt.data(
(-1, '1 day ago - {date}'), (-1, '1 day ago - {date}'),
(1, 'in 1 day - {date}') (1, 'in 1 day - {date}')
) )
@ddt.unpack @ddt.unpack
def test_render_date_string_past(self, delta, expected_date_string): def test_render_date_string_past(self, delta, expected_date_string):
self.setup_course_and_user( with freeze_time('2015-01-02'):
days_till_start=-10, self.setup_course_and_user(
verification_status='denied', days_till_start=-10,
days_till_verification_deadline=delta, verification_status='denied',
) days_till_verification_deadline=delta,
block = VerificationDeadlineDate(self.course, self.user) )
self.assertEqual(block.relative_datestring, expected_date_string) block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.relative_datestring, expected_date_string)
...@@ -1834,24 +1834,24 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems): ...@@ -1834,24 +1834,24 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems):
self.assertIsNone(student_module.grade) self.assertIsNone(student_module.grade)
self.assertIsNone(student_module.max_grade) self.assertIsNone(student_module.max_grade)
@freeze_time(datetime.now().replace(tzinfo=pytz.UTC))
@patch('lms.djangoapps.grades.signals.handlers.PROBLEM_RAW_SCORE_CHANGED.send') @patch('lms.djangoapps.grades.signals.handlers.PROBLEM_RAW_SCORE_CHANGED.send')
def test_score_change_signal(self, send_mock): def test_score_change_signal(self, send_mock):
"""Test that a Django signal is generated when a score changes""" """Test that a Django signal is generated when a score changes"""
self.set_module_grade_using_publish(self.grade_dict) with freeze_time(datetime.now().replace(tzinfo=pytz.UTC)):
expected_signal_kwargs = { self.set_module_grade_using_publish(self.grade_dict)
'sender': None, expected_signal_kwargs = {
'raw_possible': self.grade_dict['max_value'], 'sender': None,
'raw_earned': self.grade_dict['value'], 'raw_possible': self.grade_dict['max_value'],
'weight': None, 'raw_earned': self.grade_dict['value'],
'user_id': self.student_user.id, 'weight': None,
'course_id': unicode(self.course.id), 'user_id': self.student_user.id,
'usage_id': unicode(self.problem.location), 'course_id': unicode(self.course.id),
'only_if_higher': None, 'usage_id': unicode(self.problem.location),
'modified': datetime.now().replace(tzinfo=pytz.UTC), 'only_if_higher': None,
'score_db_table': 'csm', 'modified': datetime.now().replace(tzinfo=pytz.UTC),
} 'score_db_table': 'csm',
send_mock.assert_called_with(**expected_signal_kwargs) }
send_mock.assert_called_with(**expected_signal_kwargs)
@attr(shard=1) @attr(shard=1)
......
...@@ -706,32 +706,32 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -706,32 +706,32 @@ class ViewsTestCase(ModuleStoreTestCase):
('Canada/Yukon', -8), # UTC - 8 ('Canada/Yukon', -8), # UTC - 8
('Europe/Moscow', 4)) # UTC + 3 + 1 for daylight savings ('Europe/Moscow', 4)) # UTC + 3 + 1 for daylight savings
@ddt.unpack @ddt.unpack
@freeze_time('2012-01-01')
def test_submission_history_timezone(self, timezone, hour_diff): def test_submission_history_timezone(self, timezone, hour_diff):
with (override_settings(TIME_ZONE=timezone)): with freeze_time('2012-01-01'):
course = CourseFactory.create() with (override_settings(TIME_ZONE=timezone)):
course_key = course.id course = CourseFactory.create()
client = Client() course_key = course.id
admin = AdminFactory.create() client = Client()
self.assertTrue(client.login(username=admin.username, password='test')) admin = AdminFactory.create()
state_client = DjangoXBlockUserStateClient(admin) self.assertTrue(client.login(username=admin.username, password='test'))
usage_key = course_key.make_usage_key('problem', 'test-history') state_client = DjangoXBlockUserStateClient(admin)
state_client.set( usage_key = course_key.make_usage_key('problem', 'test-history')
username=admin.username, state_client.set(
block_key=usage_key, username=admin.username,
state={'field_a': 'x', 'field_b': 'y'} block_key=usage_key,
) state={'field_a': 'x', 'field_b': 'y'}
url = reverse('submission_history', kwargs={ )
'course_id': unicode(course_key), url = reverse('submission_history', kwargs={
'student_username': admin.username, 'course_id': unicode(course_key),
'location': unicode(usage_key), 'student_username': admin.username,
}) 'location': unicode(usage_key),
response = client.get(url) })
response_content = HTMLParser().unescape(response.content) response = client.get(url)
expected_time = datetime.now() + timedelta(hours=hour_diff) response_content = HTMLParser().unescape(response.content)
expected_tz = expected_time.strftime('%Z') expected_time = datetime.now() + timedelta(hours=hour_diff)
self.assertIn(expected_tz, response_content) expected_tz = expected_time.strftime('%Z')
self.assertIn(str(expected_time), response_content) self.assertIn(expected_tz, response_content)
self.assertIn(str(expected_time), response_content)
def _email_opt_in_checkbox(self, response, org_name_string=None): def _email_opt_in_checkbox(self, response, org_name_string=None):
"""Check if the email opt-in checkbox appears in the response content.""" """Check if the email opt-in checkbox appears in the response content."""
......
...@@ -97,6 +97,7 @@ from openedx.features.course_experience import ( ...@@ -97,6 +97,7 @@ from openedx.features.course_experience import (
UNIFIED_COURSE_VIEW_FLAG, UNIFIED_COURSE_VIEW_FLAG,
) )
from openedx.features.enterprise_support.api import data_sharing_consent_required from openedx.features.enterprise_support.api import data_sharing_consent_required
from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView
from shoppingcart.utils import is_shopping_cart_enabled from shoppingcart.utils import is_shopping_cart_enabled
from student.models import UserTestGroup, CourseEnrollment from student.models import UserTestGroup, CourseEnrollment
from survey.utils import must_answer_survey from survey.utils import must_answer_survey
...@@ -330,6 +331,12 @@ def course_info(request, course_id): ...@@ -330,6 +331,12 @@ def course_info(request, course_id):
store_upgrade_cookie = False store_upgrade_cookie = False
upgrade_cookie_name = 'show_upgrade_notification' upgrade_cookie_name = 'show_upgrade_notification'
upgrade_link = None upgrade_link = None
# Construct the dates fragment
dates_fragment = None
if SelfPacedConfiguration.current().enable_course_home_improvements:
dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id)
if request.user.is_authenticated(): if request.user.is_authenticated():
show_upgrade_notification = False show_upgrade_notification = False
if request.GET.get('upgrade', 'false') == 'true': if request.GET.get('upgrade', 'false') == 'true':
...@@ -357,6 +364,7 @@ def course_info(request, course_id): ...@@ -357,6 +364,7 @@ def course_info(request, course_id):
'supports_preview_menu': True, 'supports_preview_menu': True,
'studio_url': get_studio_url(course, 'course_info'), 'studio_url': get_studio_url(course, 'course_info'),
'show_enroll_banner': show_enroll_banner, 'show_enroll_banner': show_enroll_banner,
'dates_fragment': dates_fragment,
'url_to_enroll': url_to_enroll, 'url_to_enroll': url_to_enroll,
'upgrade_link': upgrade_link, 'upgrade_link': upgrade_link,
} }
......
...@@ -266,13 +266,13 @@ class PersistentSubsectionGradeTest(GradesModelTestCase): ...@@ -266,13 +266,13 @@ class PersistentSubsectionGradeTest(GradesModelTestCase):
(True, datetime(2000, 1, 1, 12, 30, 45, tzinfo=pytz.UTC)), (True, datetime(2000, 1, 1, 12, 30, 45, tzinfo=pytz.UTC)),
(False, None), # Use as now(). Freeze time needs this calculation to happen at test time. (False, None), # Use as now(). Freeze time needs this calculation to happen at test time.
) )
@freeze_time(now())
def test_update_or_create_attempted(self, is_active, expected_first_attempted): def test_update_or_create_attempted(self, is_active, expected_first_attempted):
if expected_first_attempted is None: with freeze_time(now()):
expected_first_attempted = now() if expected_first_attempted is None:
with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active): expected_first_attempted = now()
grade = PersistentSubsectionGrade.update_or_create_grade(**self.params) with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active):
self.assertEqual(grade.first_attempted, expected_first_attempted) grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
self.assertEqual(grade.first_attempted, expected_first_attempted)
def test_unattempted(self): def test_unattempted(self):
self.params['first_attempted'] = None self.params['first_attempted'] = None
...@@ -407,10 +407,10 @@ class PersistentCourseGradesTest(GradesModelTestCase): ...@@ -407,10 +407,10 @@ class PersistentCourseGradesTest(GradesModelTestCase):
self.assertEqual(grade.letter_grade, u'') self.assertEqual(grade.letter_grade, u'')
self.assertEqual(grade.passed_timestamp, passed_timestamp) self.assertEqual(grade.passed_timestamp, passed_timestamp)
@freeze_time(now())
def test_passed_timestamp_is_now(self): def test_passed_timestamp_is_now(self):
grade = PersistentCourseGrade.update_or_create(**self.params) with freeze_time(now()):
self.assertEqual(now(), grade.passed_timestamp) grade = PersistentCourseGrade.update_or_create(**self.params)
self.assertEqual(now(), grade.passed_timestamp)
def test_create_and_read_grade(self): def test_create_and_read_grade(self):
created_grade = PersistentCourseGrade.update_or_create(**self.params) created_grade = PersistentCourseGrade.update_or_create(**self.params)
......
...@@ -2332,10 +2332,10 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase): ...@@ -2332,10 +2332,10 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase):
response = upload_ora2_data(None, None, self.course.id, None, 'generated') response = upload_ora2_data(None, None, self.course.id, None, 'generated')
self.assertEqual(response, UPDATE_STATUS_FAILED) self.assertEqual(response, UPDATE_STATUS_FAILED)
@freeze_time('2001-01-01 00:00:00')
def test_report_stores_results(self): def test_report_stores_results(self):
test_header = ['field1', 'field2'] with freeze_time('2001-01-01 00:00:00'):
test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']] test_header = ['field1', 'field2']
test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']]
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') as mock_current_task: with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') as mock_current_task:
mock_current_task.return_value = self.current_task mock_current_task.return_value = self.current_task
...@@ -2344,7 +2344,6 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase): ...@@ -2344,7 +2344,6 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase):
'lms.djangoapps.instructor_task.tasks_helper.misc.OraAggregateData.collect_ora2_data' 'lms.djangoapps.instructor_task.tasks_helper.misc.OraAggregateData.collect_ora2_data'
) as mock_collect_data: ) as mock_collect_data:
mock_collect_data.return_value = (test_header, test_rows) mock_collect_data.return_value = (test_header, test_rows)
with patch( with patch(
'lms.djangoapps.instructor_task.models.DjangoStorageReportStore.store_rows' 'lms.djangoapps.instructor_task.models.DjangoStorageReportStore.store_rows'
) as mock_store_rows: ) as mock_store_rows:
......
...@@ -87,3 +87,63 @@ ...@@ -87,3 +87,63 @@
} }
} }
} }
// date summary
.date-summary-container {
.date-summary {
@include clearfix;
padding: 10px;
@include border-left(3px solid $gray-l3);
.heading {
@extend %t-title7;
color: $gray-d2;
}
.description {
margin-top: $baseline/2;
margin-bottom: $baseline/2;
display: inline-block;
color: $gray-d1;
@extend %t-title8;
}
.date-summary-link {
@extend %t-title8;
font-weight: $font-semibold;
a {
color: $link-color;
font-weight: normal;
}
}
.date {
color: $gray-d1;
@extend %t-title9;
}
&-todays-date {
@include border-left(3px solid $blue);
.heading {
@extend %t-title8;
}
}
&-verified-upgrade-deadline {
@include border-left(3px solid $green);
}
&-verification-deadline-passed {
@include border-left(3px solid $red);
}
&-verification-deadline-retry {
@include border-left(3px solid $red);
}
&-verification-deadline-upcoming {
@include border-left(3px solid $orange);
}
}
}
...@@ -115,34 +115,8 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -115,34 +115,8 @@ from openedx.core.djangolib.markup import HTML, Text
<section aria-label="${_('Handout Navigation')}" class="handouts"> <section aria-label="${_('Handout Navigation')}" class="handouts">
% if SelfPacedConfiguration.current().enable_course_home_improvements: % if SelfPacedConfiguration.current().enable_course_home_improvements:
<h3 class="hd hd-3 handouts-header">${_("Important Course Dates")}</h3> ${HTML(dates_fragment.body_html())}
## Should be organized by date, last date appearing at the bottom % endif
% for course_date in get_course_date_blocks(course, user):
<div class="date-summary-container">
<div class="date-summary date-summary-${course_date.css_class}">
% if course_date.title:
% if course_date.title == 'current_datetime':
<span class="hd hd-4 heading localized-datetime" data-datetime="${course_date.date}" data-string="${_(u'Today is {date}')}" data-timezone="${user_timezone}" data-language="${user_language}"></span>
% else:
<span class="hd hd-4 heading">${course_date.title}</span>
% endif
% endif
% if course_date.date and course_date.title != 'current_datetime':
<p class="hd hd-4 date localized-datetime" data-format="shortDate" data-datetime="${course_date.date}" data-timezone="${user_timezone}" data-language="${user_language}" data-string="${_(course_date.relative_datestring)}"></p>
% endif
% if course_date.description:
<p class="description">${course_date.description}</p>
% endif
% if course_date.link and course_date.link_text:
<span class="date-summary-link">
<a href="${course_date.link}">${course_date.link_text}</a>
</span>
% endif
</div>
</div>
% endfor
% endif
<h3 class="hd hd-3 handouts-header">${_(course.info_sidebar_name)}</h3> <h3 class="hd hd-3 handouts-header">${_(course.info_sidebar_name)}</h3>
${HTML(get_course_info_section(request, masquerade_user, course, 'handouts'))} ${HTML(get_course_info_section(request, masquerade_user, course, 'handouts'))}
</section> </section>
......
...@@ -17,7 +17,6 @@ FROZEN_TIME = '2015-01-01' ...@@ -17,7 +17,6 @@ FROZEN_TIME = '2015-01-01'
VERIFY_STUDENT = {'DAYS_GOOD_FOR': 365} VERIFY_STUDENT = {'DAYS_GOOD_FOR': 365}
@freezegun.freeze_time(FROZEN_TIME)
@override_settings(VERIFY_STUDENT=VERIFY_STUDENT) @override_settings(VERIFY_STUDENT=VERIFY_STUDENT)
class PhotoVerificationStatusViewTests(TestCase): class PhotoVerificationStatusViewTests(TestCase):
""" Tests for the PhotoVerificationStatusView endpoint. """ """ Tests for the PhotoVerificationStatusView endpoint. """
...@@ -25,6 +24,10 @@ class PhotoVerificationStatusViewTests(TestCase): ...@@ -25,6 +24,10 @@ class PhotoVerificationStatusViewTests(TestCase):
PASSWORD = 'test' PASSWORD = 'test'
def setUp(self): def setUp(self):
freezer = freezegun.freeze_time(FROZEN_TIME)
freezer.start()
self.addCleanup(freezer.stop)
super(PhotoVerificationStatusViewTests, self).setUp() super(PhotoVerificationStatusViewTests, self).setUp()
self.user = UserFactory(password=self.PASSWORD) self.user = UserFactory(password=self.PASSWORD)
self.staff = UserFactory(is_staff=True, password=self.PASSWORD) self.staff = UserFactory(is_staff=True, password=self.PASSWORD)
......
...@@ -44,38 +44,38 @@ class TestTimeZoneUtils(TestCase): ...@@ -44,38 +44,38 @@ class TestTimeZoneUtils(TestCase):
self.assertEqual(display_tz_info['abbr'], expected_abbr) self.assertEqual(display_tz_info['abbr'], expected_abbr)
self.assertEqual(display_tz_info['offset'], expected_offset) self.assertEqual(display_tz_info['offset'], expected_offset)
@freeze_time("2015-02-09")
def test_display_time_zone_without_dst(self): def test_display_time_zone_without_dst(self):
""" """
Test to ensure get_display_time_zone() returns full display string when no kwargs specified Test to ensure get_display_time_zone() returns full display string when no kwargs specified
and returns just abbreviation or offset when specified and returns just abbreviation or offset when specified
""" """
tz_info = self._display_time_zone_helper('America/Los_Angeles') with freeze_time("2015-02-09"):
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800')
@freeze_time("2015-04-02")
def test_display_time_zone_with_dst(self): def test_display_time_zone_with_dst(self):
""" """
Test to ensure get_display_time_zone() returns modified abbreviations and Test to ensure get_display_time_zone() returns modified abbreviations and
offsets during daylight savings time. offsets during daylight savings time.
""" """
tz_info = self._display_time_zone_helper('America/Los_Angeles') with freeze_time("2015-04-02"):
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700')
@freeze_time("2015-11-01 08:59:00")
def test_display_time_zone_ambiguous_before(self): def test_display_time_zone_ambiguous_before(self):
""" """
Test to ensure get_display_time_zone() returns correct abbreviations and offsets Test to ensure get_display_time_zone() returns correct abbreviations and offsets
during ambiguous time periods (e.g. when DST is about to start/end) before the change during ambiguous time periods (e.g. when DST is about to start/end) before the change
""" """
tz_info = self._display_time_zone_helper('America/Los_Angeles') with freeze_time("2015-11-01 08:59:00"):
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700')
@freeze_time("2015-11-01 09:00:00")
def test_display_time_zone_ambiguous_after(self): def test_display_time_zone_ambiguous_after(self):
""" """
Test to ensure get_display_time_zone() returns correct abbreviations and offsets Test to ensure get_display_time_zone() returns correct abbreviations and offsets
during ambiguous time periods (e.g. when DST is about to start/end) after the change during ambiguous time periods (e.g. when DST is about to start/end) after the change
""" """
tz_info = self._display_time_zone_helper('America/Los_Angeles') with freeze_time("2015-11-01 09:00:00"):
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800')
## mako
<%page expression_filter="h"/>
<%namespace name='static' file='../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
%>
<h3 class="hd hd-6 handouts-header">${_("Important Course Dates")}</h3>
## Should be organized by date, last date appearing at the bottom
% for course_date in course_date_blocks:
<div class="date-summary-container">
<div class="date-summary date-summary-${course_date.css_class}">
% if course_date.title:
% if course_date.title == 'current_datetime':
<span class="hd hd-6 heading localized-datetime" data-datetime="${course_date.date}" data-string="${_(u'Today is {date}')}" data-timezone="${user_timezone}" data-language="${user_language}"></span>
% else:
<span class="hd hd-6 heading">${course_date.title}</span>
% endif
% endif
% if course_date.date and course_date.title != 'current_datetime':
<p class="hd hd-6 date localized-datetime" data-format="shortDate" data-datetime="${course_date.date}" data-timezone="${user_timezone}" data-language="${user_language}" data-string="${_(course_date.relative_datestring)}"></p>
% endif
% if course_date.description:
<p class="description">${course_date.description}</p>
% endif
% if course_date.link and course_date.link_text:
<span class="date-summary-link">
<a href="${course_date.link}">${course_date.link_text}</a>
</span>
% endif
</div>
</div>
% endfor
...@@ -90,6 +90,9 @@ from openedx.features.course_experience import UNIFIED_COURSE_EXPERIENCE_FLAG ...@@ -90,6 +90,9 @@ from openedx.features.course_experience import UNIFIED_COURSE_EXPERIENCE_FLAG
</li> </li>
</ul> </ul>
</div> </div>
<div class="section section-dates">
${HTML(dates_fragment.body_html())}
</div>
% if handouts_html: % if handouts_html:
<div class="section section-handouts"> <div class="section section-handouts">
<h3 class="hd-6">${_("Course Handouts")}</h3> <h3 class="hd-6">${_("Course Handouts")}</h3>
......
...@@ -65,7 +65,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase): ...@@ -65,7 +65,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
get_course_in_cache(self.course.id) get_course_in_cache(self.course.id)
# Fetch the view and verify the query counts # Fetch the view and verify the query counts
with self.assertNumQueries(35): with self.assertNumQueries(37):
with check_mongo_calls(3): with check_mongo_calls(3):
url = course_home_url(self.course) url = course_home_url(self.course)
self.client.get(url) self.client.get(url)
"""
Fragment for rendering the course dates sidebar.
"""
from django.template.loader import render_to_string
from opaque_keys.edx.keys import CourseKey
from web_fragments.fragment import Fragment
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from courseware.courses import get_course_with_access, get_course_date_blocks
class CourseDatesFragmentView(EdxFragmentView):
"""
A fragment to important dates within a course.
"""
def render_to_fragment(self, request, course_id=None, **kwargs):
"""
Render the course dates fragment.
"""
course_key = CourseKey.from_string(course_id)
course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)
course_date_blocks = get_course_date_blocks(course, request.user)
context = {
'course_date_blocks': course_date_blocks
}
html = render_to_string('course_experience/course-dates-fragment.html', context)
return Fragment(html)
...@@ -17,6 +17,7 @@ from util.views import ensure_valid_course_key ...@@ -17,6 +17,7 @@ from util.views import ensure_valid_course_key
from web_fragments.fragment import Fragment from web_fragments.fragment import Fragment
from .course_outline import CourseOutlineFragmentView from .course_outline import CourseOutlineFragmentView
from .course_dates import CourseDatesFragmentView
from ..utils import get_course_outline_block_tree from ..utils import get_course_outline_block_tree
...@@ -92,6 +93,9 @@ class CourseHomeFragmentView(EdxFragmentView): ...@@ -92,6 +93,9 @@ class CourseHomeFragmentView(EdxFragmentView):
# Get resume course information # Get resume course information
has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id) has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id)
# Render the course dates as a fragment
dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs)
# Get the handouts # Get the handouts
# TODO: Use get_course_overview_with_access and blocks api # TODO: Use get_course_overview_with_access and blocks api
course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
...@@ -101,10 +105,12 @@ class CourseHomeFragmentView(EdxFragmentView): ...@@ -101,10 +105,12 @@ class CourseHomeFragmentView(EdxFragmentView):
context = { context = {
'csrf': csrf(request)['csrf_token'], 'csrf': csrf(request)['csrf_token'],
'course_key': course_key, 'course_key': course_key,
'course': course,
'outline_fragment': outline_fragment, 'outline_fragment': outline_fragment,
'handouts_html': handouts_html, 'handouts_html': handouts_html,
'has_visited_course': has_visited_course, 'has_visited_course': has_visited_course,
'resume_course_url': resume_course_url, 'resume_course_url': resume_course_url,
'dates_fragment': dates_fragment,
'disable_courseware_js': True, 'disable_courseware_js': True,
'uses_pattern_library': True, 'uses_pattern_library': True,
} }
......
...@@ -163,7 +163,7 @@ django-crum==0.5 ...@@ -163,7 +163,7 @@ django-crum==0.5
django_nose==1.4.1 django_nose==1.4.1
factory_boy==2.8.1 factory_boy==2.8.1
flaky==3.3.0 flaky==3.3.0
freezegun==0.1.11 freezegun==0.3.8
mock-django==0.6.9 mock-django==0.6.9
mock==1.0.1 mock==1.0.1
moto==0.3.1 moto==0.3.1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment