Add new course dates fragment.
Also add it to the course home page.
This commit is contained in:
committed by
Andy Armstrong
parent
97c084514f
commit
e12a704cea
@@ -527,19 +527,19 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest
|
||||
self.assertNotContains(response, "Schools & Partners")
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@freezegun.freeze_time('2015-01-02')
|
||||
def test_course_closed(self):
|
||||
for mode in ["honor", "verified"]:
|
||||
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
|
||||
with freezegun.freeze_time('2015-01-02'):
|
||||
for mode in ["honor", "verified"]:
|
||||
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
|
||||
|
||||
self.course.enrollment_end = datetime(2015, 01, 01)
|
||||
modulestore().update_item(self.course, self.user.id)
|
||||
self.course.enrollment_end = datetime(2015, 01, 01)
|
||||
modulestore().update_item(self.course, self.user.id)
|
||||
|
||||
url = reverse('course_modes_choose', args=[unicode(self.course.id)])
|
||||
response = self.client.get(url)
|
||||
# URL-encoded version of 1/1/15, 12:00 AM
|
||||
redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM'
|
||||
self.assertRedirects(response, redirect_url)
|
||||
url = reverse('course_modes_choose', args=[unicode(self.course.id)])
|
||||
response = self.client.get(url)
|
||||
# URL-encoded version of 1/1/15, 12:00 AM
|
||||
redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM'
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
|
||||
@@ -31,7 +31,6 @@ class InMemoryBackend(object):
|
||||
self.events.append(event)
|
||||
|
||||
|
||||
@freeze_time(FROZEN_TIME)
|
||||
@override_settings(
|
||||
EVENT_TRACKING_BACKENDS=IN_MEMORY_BACKEND_CONFIG
|
||||
)
|
||||
@@ -46,6 +45,10 @@ class EventTrackingTestCase(TestCase):
|
||||
# Make this more robust to the addition of new events that the test doesn't care about.
|
||||
|
||||
def setUp(self):
|
||||
freezer = freeze_time(FROZEN_TIME)
|
||||
freezer.start()
|
||||
self.addCleanup(freezer.stop)
|
||||
|
||||
super(EventTrackingTestCase, self).setUp()
|
||||
|
||||
self.recreate_tracker()
|
||||
|
||||
@@ -107,7 +107,7 @@ def server_track(request, event_type, event, page=None):
|
||||
"event": event,
|
||||
"agent": _get_request_header(request, 'HTTP_USER_AGENT').decode('latin1'),
|
||||
"page": page,
|
||||
"time": datetime.datetime.utcnow(),
|
||||
"time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
|
||||
"host": _get_request_header(request, 'SERVER_NAME'),
|
||||
"context": eventtracker.get_tracker().resolve_context(),
|
||||
}
|
||||
@@ -155,7 +155,7 @@ def task_track(request_info, task_info, event_type, event, page=None):
|
||||
"event": full_event,
|
||||
"agent": request_info.get('agent', 'unknown'),
|
||||
"page": page,
|
||||
"time": datetime.datetime.utcnow(),
|
||||
"time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
|
||||
"host": request_info.get('host', 'unknown'),
|
||||
"context": eventtracker.get_tracker().resolve_context(),
|
||||
}
|
||||
|
||||
@@ -139,42 +139,42 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn("'banner_text': None", html)
|
||||
|
||||
@freeze_time(COURSE_END_DATE)
|
||||
def test_hidden_content_past_due(self):
|
||||
progress_url = 'http://test_progress_link'
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
with freeze_time(COURSE_END_DATE):
|
||||
progress_url = 'http://test_progress_link'
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
|
||||
@freeze_time(COURSE_END_DATE)
|
||||
def test_masquerade_hidden_content_past_due(self):
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(specific_masquerade=True),
|
||||
)
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn(
|
||||
"'banner_text': 'Because the due date has passed, "
|
||||
"this assignment is hidden from the learner.'",
|
||||
html
|
||||
)
|
||||
with freeze_time(COURSE_END_DATE):
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(specific_masquerade=True),
|
||||
)
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn(
|
||||
"'banner_text': 'Because the due date has passed, "
|
||||
"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):
|
||||
html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True)
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn("'banner_text': None", html)
|
||||
with freeze_time(PAST_DUE_BEFORE_END_DATE):
|
||||
html = self._get_rendered_student_view(self.sequence_4_1, self_paced=True)
|
||||
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):
|
||||
progress_url = 'http://test_progress_link'
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
self_paced=True,
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
with freeze_time(COURSE_END_DATE + timedelta(days=7)):
|
||||
progress_url = 'http://test_progress_link'
|
||||
html = self._get_rendered_student_view(
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
self_paced=True,
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
|
||||
@@ -35,8 +35,11 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
|
||||
display_name='Verified Course'
|
||||
)
|
||||
|
||||
@freeze_time(now)
|
||||
def setUp(self):
|
||||
freezer = freeze_time(self.now)
|
||||
freezer.start()
|
||||
self.addCleanup(freezer.stop)
|
||||
|
||||
super(CertificatesRestApiTest, self).setUp()
|
||||
|
||||
self.student = UserFactory.create(password=USER_PASSWORD)
|
||||
|
||||
@@ -326,8 +326,10 @@ class CertificateGetTests(SharedModuleStoreTestCase):
|
||||
now = timezone.now()
|
||||
|
||||
@classmethod
|
||||
@freeze_time(now)
|
||||
def setUpClass(cls):
|
||||
cls.freezer = freeze_time(cls.now)
|
||||
cls.freezer.start()
|
||||
|
||||
super(CertificateGetTests, cls).setUpClass()
|
||||
cls.student = UserFactory()
|
||||
cls.student_no_cert = UserFactory()
|
||||
@@ -365,6 +367,10 @@ class CertificateGetTests(SharedModuleStoreTestCase):
|
||||
verify_uuid=cls.uuid,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.freezer.stop()
|
||||
|
||||
def test_get_certificate_for_user(self):
|
||||
"""
|
||||
Test to get a certificate for a user for a specific course.
|
||||
|
||||
@@ -33,39 +33,38 @@ class EdxRestApiClientTest(TestCase):
|
||||
self.user = UserFactory()
|
||||
|
||||
@httpretty.activate
|
||||
@freeze_time('2015-7-2')
|
||||
def test_tracking_context(self):
|
||||
"""
|
||||
Ensure the tracking context is set up in the api client correctly and
|
||||
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.
|
||||
httpretty.register_uri(
|
||||
httpretty.POST,
|
||||
'{}/baskets/1/'.format(settings.ECOMMERCE_API_URL.strip('/')),
|
||||
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()
|
||||
|
||||
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
|
||||
actual_header = httpretty.last_request().headers['Authorization']
|
||||
|
||||
# Verify the JWT includes the tracking context for the user
|
||||
actual_header = httpretty.last_request().headers['Authorization']
|
||||
|
||||
claims = {
|
||||
'tracking_context': {
|
||||
'lms_user_id': self.user.id, # pylint: disable=no-member
|
||||
'lms_client_id': self.TEST_CLIENT_ID,
|
||||
'lms_ip': '127.0.0.1',
|
||||
claims = {
|
||||
'tracking_context': {
|
||||
'lms_user_id': self.user.id, # pylint: disable=no-member
|
||||
'lms_client_id': self.TEST_CLIENT_ID,
|
||||
'lms_ip': '127.0.0.1',
|
||||
}
|
||||
}
|
||||
}
|
||||
expected_jwt = JwtBuilder(self.user).build_token(['email', 'profile'], additional_claims=claims)
|
||||
expected_header = 'JWT {}'.format(expected_jwt)
|
||||
self.assertEqual(actual_header, expected_header)
|
||||
expected_jwt = JwtBuilder(self.user).build_token(['email', 'profile'], additional_claims=claims)
|
||||
expected_header = 'JWT {}'.format(expected_jwt)
|
||||
self.assertEqual(actual_header, expected_header)
|
||||
|
||||
@httpretty.activate
|
||||
def test_client_unicode(self):
|
||||
|
||||
@@ -7,6 +7,8 @@ from django.core.urlresolvers import reverse
|
||||
from freezegun import freeze_time
|
||||
from nose.plugins.attrib import attr
|
||||
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 course_modes.tests.factories import CourseModeFactory
|
||||
@@ -169,56 +171,66 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
self.setup_course_and_user(**course_options)
|
||||
self.assert_block_types(expected_blocks)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_todays_date_block(self):
|
||||
"""
|
||||
Helper function to test that today's date block renders correctly
|
||||
and displays the correct time, accounting for daylight savings
|
||||
"""
|
||||
self.setup_course_and_user()
|
||||
block = TodaysDate(self.course, self.user)
|
||||
self.assertTrue(block.is_enabled)
|
||||
self.assertEqual(block.date, datetime.now(utc))
|
||||
self.assertEqual(block.title, 'current_datetime')
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user()
|
||||
block = TodaysDate(self.course, self.user)
|
||||
self.assertTrue(block.is_enabled)
|
||||
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')
|
||||
@ddt.data(
|
||||
'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.client.login(username='mrrobot', password='test')
|
||||
|
||||
html_elements = [
|
||||
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>',
|
||||
'<div class="date-summary-container">',
|
||||
'<div class="date-summary date-summary-todays-date">',
|
||||
'<span class="hd hd-4 heading localized-datetime"',
|
||||
'data-datetime="2015-01-02 00:00:00+00:00"',
|
||||
'data-string="Today is {date}"',
|
||||
'data-timezone="None"'
|
||||
]
|
||||
url = reverse('info', args=(self.course.id, ))
|
||||
response = self.client.get(url)
|
||||
for html in html_elements:
|
||||
self.assertContains(response, html)
|
||||
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="None"'
|
||||
]
|
||||
url = reverse(url_name, args=(self.course.id, ))
|
||||
response = self.client.get(url, follow=True)
|
||||
for html in html_elements:
|
||||
self.assertContains(response, html)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_todays_date_timezone(self):
|
||||
self.setup_course_and_user()
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
set_user_preference(self.user, "time_zone", "America/Los_Angeles")
|
||||
url = reverse('info', args=(self.course.id,))
|
||||
response = self.client.get(url)
|
||||
@ddt.data(
|
||||
'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.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 = [
|
||||
'<h3 class="hd hd-3 handouts-header">Important Course Dates</h3>',
|
||||
'<div class="date-summary-container">',
|
||||
'<div class="date-summary date-summary-todays-date">',
|
||||
'<span class="hd hd-4 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)
|
||||
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
|
||||
def test_course_start_date(self):
|
||||
@@ -226,33 +238,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
block = CourseStartDate(self.course, self.user)
|
||||
self.assertEqual(block.date, self.course.start)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_start_date_render(self):
|
||||
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 = [
|
||||
'data-string="in 1 day - {date}"',
|
||||
'data-datetime="2015-01-03 00:00:00+00:00"'
|
||||
]
|
||||
for html in html_elements:
|
||||
self.assertContains(response, html)
|
||||
@ddt.data(
|
||||
'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.client.login(username='mrrobot', password='test')
|
||||
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"'
|
||||
]
|
||||
for html in html_elements:
|
||||
self.assertContains(response, html)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_start_date_render_time_zone(self):
|
||||
self.setup_course_and_user()
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
set_user_preference(self.user, "time_zone", "America/Los_Angeles")
|
||||
url = reverse('info', args=(self.course.id,))
|
||||
response = self.client.get(url)
|
||||
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)
|
||||
@ddt.data(
|
||||
'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.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
|
||||
def test_course_end_date_for_certificate_eligible_mode(self):
|
||||
@@ -308,15 +330,15 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
if expected_cookie_value is not None:
|
||||
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):
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=1))
|
||||
self.assertTrue(block.is_enabled)
|
||||
self.assertEqual(block.link, reverse('verify_student_upgrade_and_verify', args=(self.course.id,)))
|
||||
self.check_upgrade_banner()
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=1))
|
||||
self.assertTrue(block.is_enabled)
|
||||
self.assertEqual(block.link, reverse('verify_student_upgrade_and_verify', args=(self.course.id,)))
|
||||
self.check_upgrade_banner()
|
||||
|
||||
def test_without_upgrade_deadline(self):
|
||||
self.setup_course_and_user(enrollment_mode=None)
|
||||
@@ -326,43 +348,43 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
self.assertIsNone(block.date)
|
||||
self.check_upgrade_banner(banner_expected=False)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
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)
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
|
||||
self.assertFalse(block.is_enabled)
|
||||
self.check_upgrade_banner(banner_expected=False)
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT)
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
|
||||
self.assertFalse(block.is_enabled)
|
||||
self.check_upgrade_banner(banner_expected=False)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_verified_upgrade_banner_cookie(self):
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
|
||||
self.client.login(username='mrrobot', password='test')
|
||||
with freeze_time('2015-01-02'):
|
||||
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.
|
||||
self.check_upgrade_banner(include_url_parameter=False, banner_expected=False)
|
||||
# No URL parameter or cookie present, notification should not be shown.
|
||||
self.check_upgrade_banner(include_url_parameter=False, banner_expected=False)
|
||||
|
||||
# Now pass URL parameter-- notification should be shown.
|
||||
self.check_upgrade_banner(include_url_parameter=True)
|
||||
# Now pass URL parameter-- notification should be shown.
|
||||
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
|
||||
# the URL parameter in order to see the notification.
|
||||
self.check_upgrade_banner(include_url_parameter=False)
|
||||
# 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.
|
||||
self.check_upgrade_banner(include_url_parameter=False)
|
||||
|
||||
# Store the current course_id for testing
|
||||
old_course_id = self.course.id
|
||||
# Store the current course_id for testing
|
||||
old_course_id = self.course.id
|
||||
|
||||
# Change to another course
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=1,
|
||||
user_enrollment_mode=CourseMode.AUDIT,
|
||||
create_user=False)
|
||||
# Change to another course
|
||||
self.setup_course_and_user(days_till_upgrade_deadline=1,
|
||||
user_enrollment_mode=CourseMode.AUDIT,
|
||||
create_user=False)
|
||||
|
||||
# Banner should not be present in the newly created course
|
||||
self.check_upgrade_banner(include_url_parameter=False,
|
||||
banner_expected=False,
|
||||
expected_cookie_value=old_course_id)
|
||||
# Banner should not be present in the newly created course
|
||||
self.check_upgrade_banner(include_url_parameter=False,
|
||||
banner_expected=False,
|
||||
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):
|
||||
"""Verify the block link redirects to ecommerce checkout if it's enabled."""
|
||||
@@ -387,63 +409,63 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertFalse(block.is_enabled)
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_verification_deadline_date_upcoming(self):
|
||||
self.setup_course_and_user(days_till_start=-1)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-upcoming')
|
||||
self.assertEqual(block.title, 'Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
|
||||
self.assertEqual(
|
||||
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,)))
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(days_till_start=-1)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-upcoming')
|
||||
self.assertEqual(block.title, 'Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
|
||||
self.assertEqual(
|
||||
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,)))
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_verification_deadline_date_retry(self):
|
||||
self.setup_course_and_user(days_till_start=-1, verification_status='denied')
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-retry')
|
||||
self.assertEqual(block.title, 'Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
|
||||
self.assertEqual(
|
||||
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'))
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(days_till_start=-1, verification_status='denied')
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-retry')
|
||||
self.assertEqual(block.title, 'Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=14))
|
||||
self.assertEqual(
|
||||
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'))
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
def test_verification_deadline_date_denied(self):
|
||||
self.setup_course_and_user(
|
||||
days_till_start=-10,
|
||||
verification_status='denied',
|
||||
days_till_verification_deadline=-1,
|
||||
)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-passed')
|
||||
self.assertEqual(block.title, 'Missed Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=-1))
|
||||
self.assertEqual(
|
||||
block.description,
|
||||
"Unfortunately you missed this course's deadline for a successful verification."
|
||||
)
|
||||
self.assertEqual(block.link_text, 'Learn More')
|
||||
self.assertEqual(block.link, '')
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(
|
||||
days_till_start=-10,
|
||||
verification_status='denied',
|
||||
days_till_verification_deadline=-1,
|
||||
)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.css_class, 'verification-deadline-passed')
|
||||
self.assertEqual(block.title, 'Missed Verification Deadline')
|
||||
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=-1))
|
||||
self.assertEqual(
|
||||
block.description,
|
||||
"Unfortunately you missed this course's deadline for a successful verification."
|
||||
)
|
||||
self.assertEqual(block.link_text, 'Learn More')
|
||||
self.assertEqual(block.link, '')
|
||||
|
||||
@freeze_time('2015-01-02')
|
||||
@ddt.data(
|
||||
(-1, '1 day ago - {date}'),
|
||||
(1, 'in 1 day - {date}')
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_render_date_string_past(self, delta, expected_date_string):
|
||||
self.setup_course_and_user(
|
||||
days_till_start=-10,
|
||||
verification_status='denied',
|
||||
days_till_verification_deadline=delta,
|
||||
)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.relative_datestring, expected_date_string)
|
||||
with freeze_time('2015-01-02'):
|
||||
self.setup_course_and_user(
|
||||
days_till_start=-10,
|
||||
verification_status='denied',
|
||||
days_till_verification_deadline=delta,
|
||||
)
|
||||
block = VerificationDeadlineDate(self.course, self.user)
|
||||
self.assertEqual(block.relative_datestring, expected_date_string)
|
||||
|
||||
@@ -1834,24 +1834,24 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems):
|
||||
self.assertIsNone(student_module.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')
|
||||
def test_score_change_signal(self, send_mock):
|
||||
"""Test that a Django signal is generated when a score changes"""
|
||||
self.set_module_grade_using_publish(self.grade_dict)
|
||||
expected_signal_kwargs = {
|
||||
'sender': None,
|
||||
'raw_possible': self.grade_dict['max_value'],
|
||||
'raw_earned': self.grade_dict['value'],
|
||||
'weight': None,
|
||||
'user_id': self.student_user.id,
|
||||
'course_id': unicode(self.course.id),
|
||||
'usage_id': unicode(self.problem.location),
|
||||
'only_if_higher': None,
|
||||
'modified': datetime.now().replace(tzinfo=pytz.UTC),
|
||||
'score_db_table': 'csm',
|
||||
}
|
||||
send_mock.assert_called_with(**expected_signal_kwargs)
|
||||
with freeze_time(datetime.now().replace(tzinfo=pytz.UTC)):
|
||||
self.set_module_grade_using_publish(self.grade_dict)
|
||||
expected_signal_kwargs = {
|
||||
'sender': None,
|
||||
'raw_possible': self.grade_dict['max_value'],
|
||||
'raw_earned': self.grade_dict['value'],
|
||||
'weight': None,
|
||||
'user_id': self.student_user.id,
|
||||
'course_id': unicode(self.course.id),
|
||||
'usage_id': unicode(self.problem.location),
|
||||
'only_if_higher': None,
|
||||
'modified': datetime.now().replace(tzinfo=pytz.UTC),
|
||||
'score_db_table': 'csm',
|
||||
}
|
||||
send_mock.assert_called_with(**expected_signal_kwargs)
|
||||
|
||||
|
||||
@attr(shard=1)
|
||||
|
||||
@@ -706,32 +706,32 @@ class ViewsTestCase(ModuleStoreTestCase):
|
||||
('Canada/Yukon', -8), # UTC - 8
|
||||
('Europe/Moscow', 4)) # UTC + 3 + 1 for daylight savings
|
||||
@ddt.unpack
|
||||
@freeze_time('2012-01-01')
|
||||
def test_submission_history_timezone(self, timezone, hour_diff):
|
||||
with (override_settings(TIME_ZONE=timezone)):
|
||||
course = CourseFactory.create()
|
||||
course_key = course.id
|
||||
client = Client()
|
||||
admin = AdminFactory.create()
|
||||
self.assertTrue(client.login(username=admin.username, password='test'))
|
||||
state_client = DjangoXBlockUserStateClient(admin)
|
||||
usage_key = course_key.make_usage_key('problem', 'test-history')
|
||||
state_client.set(
|
||||
username=admin.username,
|
||||
block_key=usage_key,
|
||||
state={'field_a': 'x', 'field_b': 'y'}
|
||||
)
|
||||
url = reverse('submission_history', kwargs={
|
||||
'course_id': unicode(course_key),
|
||||
'student_username': admin.username,
|
||||
'location': unicode(usage_key),
|
||||
})
|
||||
response = client.get(url)
|
||||
response_content = HTMLParser().unescape(response.content)
|
||||
expected_time = datetime.now() + timedelta(hours=hour_diff)
|
||||
expected_tz = expected_time.strftime('%Z')
|
||||
self.assertIn(expected_tz, response_content)
|
||||
self.assertIn(str(expected_time), response_content)
|
||||
with freeze_time('2012-01-01'):
|
||||
with (override_settings(TIME_ZONE=timezone)):
|
||||
course = CourseFactory.create()
|
||||
course_key = course.id
|
||||
client = Client()
|
||||
admin = AdminFactory.create()
|
||||
self.assertTrue(client.login(username=admin.username, password='test'))
|
||||
state_client = DjangoXBlockUserStateClient(admin)
|
||||
usage_key = course_key.make_usage_key('problem', 'test-history')
|
||||
state_client.set(
|
||||
username=admin.username,
|
||||
block_key=usage_key,
|
||||
state={'field_a': 'x', 'field_b': 'y'}
|
||||
)
|
||||
url = reverse('submission_history', kwargs={
|
||||
'course_id': unicode(course_key),
|
||||
'student_username': admin.username,
|
||||
'location': unicode(usage_key),
|
||||
})
|
||||
response = client.get(url)
|
||||
response_content = HTMLParser().unescape(response.content)
|
||||
expected_time = datetime.now() + timedelta(hours=hour_diff)
|
||||
expected_tz = expected_time.strftime('%Z')
|
||||
self.assertIn(expected_tz, response_content)
|
||||
self.assertIn(str(expected_time), response_content)
|
||||
|
||||
def _email_opt_in_checkbox(self, response, org_name_string=None):
|
||||
"""Check if the email opt-in checkbox appears in the response content."""
|
||||
|
||||
@@ -97,6 +97,7 @@ from openedx.features.course_experience import (
|
||||
UNIFIED_COURSE_VIEW_FLAG,
|
||||
)
|
||||
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 student.models import UserTestGroup, CourseEnrollment
|
||||
from survey.utils import must_answer_survey
|
||||
@@ -330,6 +331,12 @@ def course_info(request, course_id):
|
||||
store_upgrade_cookie = False
|
||||
upgrade_cookie_name = 'show_upgrade_notification'
|
||||
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():
|
||||
show_upgrade_notification = False
|
||||
if request.GET.get('upgrade', 'false') == 'true':
|
||||
@@ -357,6 +364,7 @@ def course_info(request, course_id):
|
||||
'supports_preview_menu': True,
|
||||
'studio_url': get_studio_url(course, 'course_info'),
|
||||
'show_enroll_banner': show_enroll_banner,
|
||||
'dates_fragment': dates_fragment,
|
||||
'url_to_enroll': url_to_enroll,
|
||||
'upgrade_link': upgrade_link,
|
||||
}
|
||||
|
||||
@@ -266,13 +266,13 @@ class PersistentSubsectionGradeTest(GradesModelTestCase):
|
||||
(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.
|
||||
)
|
||||
@freeze_time(now())
|
||||
def test_update_or_create_attempted(self, is_active, expected_first_attempted):
|
||||
if expected_first_attempted is None:
|
||||
expected_first_attempted = now()
|
||||
with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active):
|
||||
grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
|
||||
self.assertEqual(grade.first_attempted, expected_first_attempted)
|
||||
with freeze_time(now()):
|
||||
if expected_first_attempted is None:
|
||||
expected_first_attempted = now()
|
||||
with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active):
|
||||
grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
|
||||
self.assertEqual(grade.first_attempted, expected_first_attempted)
|
||||
|
||||
def test_unattempted(self):
|
||||
self.params['first_attempted'] = None
|
||||
@@ -407,10 +407,10 @@ class PersistentCourseGradesTest(GradesModelTestCase):
|
||||
self.assertEqual(grade.letter_grade, u'')
|
||||
self.assertEqual(grade.passed_timestamp, passed_timestamp)
|
||||
|
||||
@freeze_time(now())
|
||||
def test_passed_timestamp_is_now(self):
|
||||
grade = PersistentCourseGrade.update_or_create(**self.params)
|
||||
self.assertEqual(now(), grade.passed_timestamp)
|
||||
with freeze_time(now()):
|
||||
grade = PersistentCourseGrade.update_or_create(**self.params)
|
||||
self.assertEqual(now(), grade.passed_timestamp)
|
||||
|
||||
def test_create_and_read_grade(self):
|
||||
created_grade = PersistentCourseGrade.update_or_create(**self.params)
|
||||
|
||||
@@ -2332,10 +2332,10 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase):
|
||||
response = upload_ora2_data(None, None, self.course.id, None, 'generated')
|
||||
self.assertEqual(response, UPDATE_STATUS_FAILED)
|
||||
|
||||
@freeze_time('2001-01-01 00:00:00')
|
||||
def test_report_stores_results(self):
|
||||
test_header = ['field1', 'field2']
|
||||
test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']]
|
||||
with freeze_time('2001-01-01 00:00:00'):
|
||||
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:
|
||||
mock_current_task.return_value = self.current_task
|
||||
@@ -2344,7 +2344,6 @@ class TestInstructorOra2Report(SharedModuleStoreTestCase):
|
||||
'lms.djangoapps.instructor_task.tasks_helper.misc.OraAggregateData.collect_ora2_data'
|
||||
) as mock_collect_data:
|
||||
mock_collect_data.return_value = (test_header, test_rows)
|
||||
|
||||
with patch(
|
||||
'lms.djangoapps.instructor_task.models.DjangoStorageReportStore.store_rows'
|
||||
) as mock_store_rows:
|
||||
|
||||
@@ -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
|
||||
<section aria-label="${_('Handout Navigation')}" class="handouts">
|
||||
|
||||
% if SelfPacedConfiguration.current().enable_course_home_improvements:
|
||||
<h3 class="hd hd-3 handouts-header">${_("Important Course Dates")}</h3>
|
||||
## 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
|
||||
${HTML(dates_fragment.body_html())}
|
||||
% endif
|
||||
<h3 class="hd hd-3 handouts-header">${_(course.info_sidebar_name)}</h3>
|
||||
${HTML(get_course_info_section(request, masquerade_user, course, 'handouts'))}
|
||||
</section>
|
||||
|
||||
@@ -17,7 +17,6 @@ FROZEN_TIME = '2015-01-01'
|
||||
VERIFY_STUDENT = {'DAYS_GOOD_FOR': 365}
|
||||
|
||||
|
||||
@freezegun.freeze_time(FROZEN_TIME)
|
||||
@override_settings(VERIFY_STUDENT=VERIFY_STUDENT)
|
||||
class PhotoVerificationStatusViewTests(TestCase):
|
||||
""" Tests for the PhotoVerificationStatusView endpoint. """
|
||||
@@ -25,6 +24,10 @@ class PhotoVerificationStatusViewTests(TestCase):
|
||||
PASSWORD = 'test'
|
||||
|
||||
def setUp(self):
|
||||
freezer = freezegun.freeze_time(FROZEN_TIME)
|
||||
freezer.start()
|
||||
self.addCleanup(freezer.stop)
|
||||
|
||||
super(PhotoVerificationStatusViewTests, self).setUp()
|
||||
self.user = UserFactory(password=self.PASSWORD)
|
||||
self.staff = UserFactory(is_staff=True, password=self.PASSWORD)
|
||||
|
||||
@@ -44,38 +44,38 @@ class TestTimeZoneUtils(TestCase):
|
||||
self.assertEqual(display_tz_info['abbr'], expected_abbr)
|
||||
self.assertEqual(display_tz_info['offset'], expected_offset)
|
||||
|
||||
@freeze_time("2015-02-09")
|
||||
def test_display_time_zone_without_dst(self):
|
||||
"""
|
||||
Test to ensure get_display_time_zone() returns full display string when no kwargs specified
|
||||
and returns just abbreviation or offset when specified
|
||||
"""
|
||||
tz_info = self._display_time_zone_helper('America/Los_Angeles')
|
||||
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800')
|
||||
with freeze_time("2015-02-09"):
|
||||
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):
|
||||
"""
|
||||
Test to ensure get_display_time_zone() returns modified abbreviations and
|
||||
offsets during daylight savings time.
|
||||
"""
|
||||
tz_info = self._display_time_zone_helper('America/Los_Angeles')
|
||||
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700')
|
||||
with freeze_time("2015-04-02"):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
tz_info = self._display_time_zone_helper('America/Los_Angeles')
|
||||
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PDT', '-0700')
|
||||
with freeze_time("2015-11-01 08:59:00"):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
tz_info = self._display_time_zone_helper('America/Los_Angeles')
|
||||
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800')
|
||||
with freeze_time("2015-11-01 09:00:00"):
|
||||
tz_info = self._display_time_zone_helper('America/Los_Angeles')
|
||||
self._assert_time_zone_info_equal(tz_info, 'America/Los Angeles', 'PST', '-0800')
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
## 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
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section section-dates">
|
||||
${HTML(dates_fragment.body_html())}
|
||||
</div>
|
||||
% if handouts_html:
|
||||
<div class="section section-handouts">
|
||||
<h3 class="hd-6">${_("Course Handouts")}</h3>
|
||||
|
||||
@@ -65,7 +65,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
|
||||
get_course_in_cache(self.course.id)
|
||||
|
||||
# Fetch the view and verify the query counts
|
||||
with self.assertNumQueries(35):
|
||||
with self.assertNumQueries(37):
|
||||
with check_mongo_calls(3):
|
||||
url = course_home_url(self.course)
|
||||
self.client.get(url)
|
||||
|
||||
27
openedx/features/course_experience/views/course_dates.py
Normal file
27
openedx/features/course_experience/views/course_dates.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
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
|
||||
from web_fragments.fragment import Fragment
|
||||
|
||||
from .course_outline import CourseOutlineFragmentView
|
||||
from .course_dates import CourseDatesFragmentView
|
||||
from ..utils import get_course_outline_block_tree
|
||||
|
||||
|
||||
@@ -92,6 +93,9 @@ class CourseHomeFragmentView(EdxFragmentView):
|
||||
# Get resume course information
|
||||
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
|
||||
# TODO: Use get_course_overview_with_access and blocks api
|
||||
course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
|
||||
@@ -101,10 +105,12 @@ class CourseHomeFragmentView(EdxFragmentView):
|
||||
context = {
|
||||
'csrf': csrf(request)['csrf_token'],
|
||||
'course_key': course_key,
|
||||
'course': course,
|
||||
'outline_fragment': outline_fragment,
|
||||
'handouts_html': handouts_html,
|
||||
'has_visited_course': has_visited_course,
|
||||
'resume_course_url': resume_course_url,
|
||||
'dates_fragment': dates_fragment,
|
||||
'disable_courseware_js': True,
|
||||
'uses_pattern_library': True,
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ django-crum==0.5
|
||||
django_nose==1.4.1
|
||||
factory_boy==2.8.1
|
||||
flaky==3.3.0
|
||||
freezegun==0.1.11
|
||||
freezegun==0.3.8
|
||||
mock-django==0.6.9
|
||||
mock==1.0.1
|
||||
moto==0.3.1
|
||||
|
||||
Reference in New Issue
Block a user