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,8 +527,8 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest ...@@ -527,8 +527,8 @@ 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):
with freezegun.freeze_time('2015-01-02'):
for mode in ["honor", "verified"]: for mode in ["honor", "verified"]:
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory(mode_slug=mode, course_id=self.course.id)
......
...@@ -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,8 +139,8 @@ class SequenceBlockTestCase(XModuleXmlImportTest): ...@@ -139,8 +139,8 @@ 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):
with freeze_time(COURSE_END_DATE):
progress_url = 'http://test_progress_link' progress_url = 'http://test_progress_link'
html = self._get_rendered_student_view( html = self._get_rendered_student_view(
self.sequence_4_1, self.sequence_4_1,
...@@ -149,8 +149,8 @@ class SequenceBlockTestCase(XModuleXmlImportTest): ...@@ -149,8 +149,8 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
self.assertIn("hidden_content.html", html) self.assertIn("hidden_content.html", html)
self.assertIn(progress_url, 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):
with freeze_time(COURSE_END_DATE):
html = self._get_rendered_student_view( html = self._get_rendered_student_view(
self.sequence_4_1, self.sequence_4_1,
extra_context=dict(specific_masquerade=True), extra_context=dict(specific_masquerade=True),
...@@ -162,14 +162,14 @@ class SequenceBlockTestCase(XModuleXmlImportTest): ...@@ -162,14 +162,14 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
html 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):
with freeze_time(PAST_DUE_BEFORE_END_DATE):
html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True) html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True)
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 + timedelta(days=7))
def test_hidden_content_self_paced_past_end(self): def test_hidden_content_self_paced_past_end(self):
with freeze_time(COURSE_END_DATE + timedelta(days=7)):
progress_url = 'http://test_progress_link' progress_url = 'http://test_progress_link'
html = self._get_rendered_student_view( html = self._get_rendered_student_view(
self.sequence_4_1, self.sequence_4_1,
......
...@@ -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,13 +33,12 @@ class EdxRestApiClientTest(TestCase): ...@@ -33,13 +33,12 @@ 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. # fake an E-Commerce API request.
httpretty.register_uri( httpretty.register_uri(
httpretty.POST, httpretty.POST,
......
...@@ -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,50 +171,60 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -169,50 +171,60 @@ 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
""" """
with freeze_time('2015-01-02'):
self.setup_course_and_user() self.setup_course_and_user()
block = TodaysDate(self.course, self.user) block = TodaysDate(self.course, self.user)
self.assertTrue(block.is_enabled) self.assertTrue(block.is_enabled)
self.assertEqual(block.date, datetime.now(utc)) self.assertEqual(block.date, datetime.now(utc))
self.assertEqual(block.title, 'current_datetime') self.assertEqual(block.title, 'current_datetime')
@freeze_time('2015-01-02') @ddt.data(
def test_todays_date_no_timezone(self): 'info',
'openedx.course_experience.course_home',
)
@override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
def test_todays_date_no_timezone(self, url_name):
with freeze_time('2015-01-02'):
self.setup_course_and_user() self.setup_course_and_user()
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
html_elements = [ html_elements = [
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>', '<h3 class="hd hd-6 handouts-header">Important Course Dates</h3>',
'<div class="date-summary-container">', '<div class="date-summary-container">',
'<div class="date-summary date-summary-todays-date">', '<div class="date-summary date-summary-todays-date">',
'<span class="hd hd-4 heading localized-datetime"', '<span class="hd hd-6 heading localized-datetime"',
'data-datetime="2015-01-02 00:00:00+00:00"', 'data-datetime="2015-01-02 00:00:00+00:00"',
'data-string="Today is {date}"', 'data-string="Today is {date}"',
'data-timezone="None"' 'data-timezone="None"'
] ]
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: for html in html_elements:
self.assertContains(response, html) self.assertContains(response, html)
@freeze_time('2015-01-02') @ddt.data(
def test_todays_date_timezone(self): 'info',
'openedx.course_experience.course_home',
)
@override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
def test_todays_date_timezone(self, url_name):
with freeze_time('2015-01-02'):
self.setup_course_and_user() self.setup_course_and_user()
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
set_user_preference(self.user, "time_zone", "America/Los_Angeles") 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)
html_elements = [ html_elements = [
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>', '<h3 class="hd hd-6 handouts-header">Important Course Dates</h3>',
'<div class="date-summary-container">', '<div class="date-summary-container">',
'<div class="date-summary date-summary-todays-date">', '<div class="date-summary date-summary-todays-date">',
'<span class="hd hd-4 heading localized-datetime"', '<span class="hd hd-6 heading localized-datetime"',
'data-datetime="2015-01-02 00:00:00+00:00"', 'data-datetime="2015-01-02 00:00:00+00:00"',
'data-string="Today is {date}"', 'data-string="Today is {date}"',
'data-timezone="America/Los_Angeles"' 'data-timezone="America/Los_Angeles"'
...@@ -226,12 +238,17 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -226,12 +238,17 @@ 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',
'openedx.course_experience.course_home',
)
@override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
def test_start_date_render(self, url_name):
with freeze_time('2015-01-02'):
self.setup_course_and_user() self.setup_course_and_user()
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
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)
html_elements = [ html_elements = [
'data-string="in 1 day - {date}"', 'data-string="in 1 day - {date}"',
'data-datetime="2015-01-03 00:00:00+00:00"' 'data-datetime="2015-01-03 00:00:00+00:00"'
...@@ -239,13 +256,18 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -239,13 +256,18 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
for html in html_elements: for html in html_elements:
self.assertContains(response, html) self.assertContains(response, html)
@freeze_time('2015-01-02') @ddt.data(
def test_start_date_render_time_zone(self): 'info',
'openedx.course_experience.course_home',
)
@override_flag(UNIFIED_COURSE_EXPERIENCE_FLAG, active=True)
def test_start_date_render_time_zone(self, url_name):
with freeze_time('2015-01-02'):
self.setup_course_and_user() self.setup_course_and_user()
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
set_user_preference(self.user, "time_zone", "America/Los_Angeles") 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)
html_elements = [ html_elements = [
'data-string="in 1 day - {date}"', 'data-string="in 1 day - {date}"',
'data-datetime="2015-01-03 00:00:00+00:00"', 'data-datetime="2015-01-03 00:00:00+00:00"',
...@@ -308,8 +330,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -308,8 +330,8 @@ 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT) self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
block = VerifiedUpgradeDeadlineDate(self.course, self.user) block = VerifiedUpgradeDeadlineDate(self.course, self.user)
...@@ -326,16 +348,16 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -326,16 +348,16 @@ 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT) self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
block = VerifiedUpgradeDeadlineDate(self.course, self.user) block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.assertFalse(block.is_enabled) self.assertFalse(block.is_enabled)
self.check_upgrade_banner(banner_expected=False) 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT) self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test') self.client.login(username='mrrobot', password='test')
...@@ -387,8 +409,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -387,8 +409,8 @@ 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user(days_till_start=-1) self.setup_course_and_user(days_till_start=-1)
block = VerificationDeadlineDate(self.course, self.user) block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.css_class, 'verification-deadline-upcoming') self.assertEqual(block.css_class, 'verification-deadline-upcoming')
...@@ -401,8 +423,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -401,8 +423,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertEqual(block.link_text, 'Verify My Identity') 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, 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user(days_till_start=-1, verification_status='denied') self.setup_course_and_user(days_till_start=-1, verification_status='denied')
block = VerificationDeadlineDate(self.course, self.user) block = VerificationDeadlineDate(self.course, self.user)
self.assertEqual(block.css_class, 'verification-deadline-retry') self.assertEqual(block.css_class, 'verification-deadline-retry')
...@@ -415,8 +437,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -415,8 +437,8 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertEqual(block.link_text, 'Retry Verification') self.assertEqual(block.link_text, 'Retry Verification')
self.assertEqual(block.link, reverse('verify_student_reverify')) 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user( self.setup_course_and_user(
days_till_start=-10, days_till_start=-10,
verification_status='denied', verification_status='denied',
...@@ -433,13 +455,13 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -433,13 +455,13 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertEqual(block.link_text, 'Learn More') self.assertEqual(block.link_text, 'Learn More')
self.assertEqual(block.link, '') 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):
with freeze_time('2015-01-02'):
self.setup_course_and_user( self.setup_course_and_user(
days_till_start=-10, days_till_start=-10,
verification_status='denied', verification_status='denied',
......
...@@ -1834,10 +1834,10 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems): ...@@ -1834,10 +1834,10 @@ 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"""
with freeze_time(datetime.now().replace(tzinfo=pytz.UTC)):
self.set_module_grade_using_publish(self.grade_dict) self.set_module_grade_using_publish(self.grade_dict)
expected_signal_kwargs = { expected_signal_kwargs = {
'sender': None, 'sender': None,
......
...@@ -706,8 +706,8 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -706,8 +706,8 @@ 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 freeze_time('2012-01-01'):
with (override_settings(TIME_ZONE=timezone)): with (override_settings(TIME_ZONE=timezone)):
course = CourseFactory.create() course = CourseFactory.create()
course_key = course.id course_key = course.id
......
...@@ -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,8 +266,8 @@ class PersistentSubsectionGradeTest(GradesModelTestCase): ...@@ -266,8 +266,8 @@ 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):
with freeze_time(now()):
if expected_first_attempted is None: if expected_first_attempted is None:
expected_first_attempted = now() expected_first_attempted = now()
with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active): with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active):
...@@ -407,8 +407,8 @@ class PersistentCourseGradesTest(GradesModelTestCase): ...@@ -407,8 +407,8 @@ 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):
with freeze_time(now()):
grade = PersistentCourseGrade.update_or_create(**self.params) grade = PersistentCourseGrade.update_or_create(**self.params)
self.assertEqual(now(), grade.passed_timestamp) self.assertEqual(now(), grade.passed_timestamp)
......
...@@ -2332,8 +2332,8 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase): ...@@ -2332,8 +2332,8 @@ 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):
with freeze_time('2001-01-01 00:00:00'):
test_header = ['field1', 'field2'] test_header = ['field1', 'field2']
test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']] test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']]
...@@ -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,33 +115,7 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -115,33 +115,7 @@ 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
% 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 % 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'))}
......
...@@ -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
""" """
with freeze_time("2015-02-09"):
tz_info = self._display_time_zone_helper('America/Los_Angeles') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800') 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.
""" """
with freeze_time("2015-04-02"):
tz_info = self._display_time_zone_helper('America/Los_Angeles') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700') 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
""" """
with freeze_time("2015-11-01 08:59:00"):
tz_info = self._display_time_zone_helper('America/Los_Angeles') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700') 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
""" """
with freeze_time("2015-11-01 09:00:00"):
tz_info = self._display_time_zone_helper('America/Los_Angeles') tz_info = self._display_time_zone_helper('America/Los_Angeles')
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800') 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