Revert "Merge pull request #13915 from edx/revert-13794-yro_implement-dateutil"
This reverts commitd59ab18b27, reversing changes made to0ebab35e89.
This commit is contained in:
46
lms/djangoapps/courseware/context_processor.py
Normal file
46
lms/djangoapps/courseware/context_processor.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
This is the courseware context_processor module.
|
||||
|
||||
This is meant to simplify the process of sending user preferences (espec. time_zone and pref-lang)
|
||||
to the templates without having to append every view file.
|
||||
|
||||
"""
|
||||
from openedx.core.djangoapps.user_api.errors import UserNotFound, UserAPIInternalError
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preferences
|
||||
import request_cache
|
||||
|
||||
RETRIEVABLE_PREFERENCES = {
|
||||
'user_timezone': 'time_zone',
|
||||
'user_language': 'pref-lang'
|
||||
}
|
||||
CACHE_NAME = "context_processor.user_timezone_preferences"
|
||||
|
||||
|
||||
def user_timezone_locale_prefs(request):
|
||||
"""
|
||||
Checks if request has an authenticated user.
|
||||
If so, sends set (or none if unset) time_zone and language prefs.
|
||||
|
||||
This interacts with the DateUtils to either display preferred or attempt to determine
|
||||
system/browser set time_zones and languages
|
||||
|
||||
"""
|
||||
cached_value = request_cache.get_cache(CACHE_NAME)
|
||||
if not cached_value:
|
||||
user_prefs = {
|
||||
'user_timezone': None,
|
||||
'user_language': None,
|
||||
}
|
||||
if hasattr(request, 'user') and request.user.is_authenticated():
|
||||
try:
|
||||
user_preferences = get_user_preferences(request.user)
|
||||
except (UserNotFound, UserAPIInternalError):
|
||||
cached_value.update(user_prefs)
|
||||
else:
|
||||
user_prefs = {
|
||||
key: user_preferences.get(pref_name, None)
|
||||
for key, pref_name in RETRIEVABLE_PREFERENCES.iteritems()
|
||||
}
|
||||
|
||||
cached_value.update(user_prefs)
|
||||
return cached_value
|
||||
@@ -4,6 +4,7 @@ page. Each block gives information about a particular
|
||||
course-run-specific date which will be displayed to the user.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from pytz import timezone, utc
|
||||
|
||||
from babel.dates import format_timedelta
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -12,13 +13,12 @@ from django.utils.translation import ugettext_lazy
|
||||
from django.utils.translation import to_locale, get_language
|
||||
from edxmako.shortcuts import render_to_string
|
||||
from lazy import lazy
|
||||
from pytz import utc
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline, SoftwareSecurePhotoVerification
|
||||
from openedx.core.lib.time_zone_utils import get_time_zone_abbr, get_user_time_zone
|
||||
from student.models import CourseEnrollment
|
||||
from openedx.core.lib.time_zone_utils import get_time_zone_abbr
|
||||
|
||||
|
||||
class DateSummary(object):
|
||||
@@ -67,8 +67,12 @@ class DateSummary(object):
|
||||
|
||||
@property
|
||||
def time_zone(self):
|
||||
"""The time zone to display in"""
|
||||
return get_user_time_zone(self.user)
|
||||
"""
|
||||
The time zone in which to display -- defaults to UTC
|
||||
"""
|
||||
return timezone(
|
||||
self.user.preferences.model.get_value(self.user, "time_zone", "UTC")
|
||||
)
|
||||
|
||||
def __init__(self, course, user):
|
||||
self.course = course
|
||||
|
||||
43
lms/djangoapps/courseware/tests/test_context_processor.py
Normal file
43
lms/djangoapps/courseware/tests/test_context_processor.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Unit tests for courseware context_processor
|
||||
"""
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from mock import Mock
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
|
||||
|
||||
from courseware.context_processor import user_timezone_locale_prefs
|
||||
|
||||
|
||||
class UserPrefContextProcessorUnitTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Unit test for courseware context_processor
|
||||
"""
|
||||
def setUp(self):
|
||||
super(UserPrefContextProcessorUnitTest, self).setUp()
|
||||
|
||||
self.user = UserFactory.create()
|
||||
self.request = Mock()
|
||||
self.request.user = self.user
|
||||
|
||||
def test_anonymous_user(self):
|
||||
self.request.user = AnonymousUser()
|
||||
context = user_timezone_locale_prefs(self.request)
|
||||
self.assertIsNone(context['user_timezone'])
|
||||
self.assertIsNone(context['user_language'])
|
||||
|
||||
def test_no_timezone_preference(self):
|
||||
set_user_preference(self.user, 'pref-lang', 'en')
|
||||
context = user_timezone_locale_prefs(self.request)
|
||||
self.assertIsNone(context['user_timezone'])
|
||||
self.assertIsNotNone(context['user_language'])
|
||||
self.assertEqual(context['user_language'], 'en')
|
||||
|
||||
def test_no_language_preference(self):
|
||||
set_user_preference(self.user, 'time_zone', 'Asia/Tokyo')
|
||||
context = user_timezone_locale_prefs(self.request)
|
||||
self.assertIsNone(context['user_language'])
|
||||
self.assertIsNotNone(context['user_timezone'])
|
||||
self.assertEqual(context['user_timezone'], 'Asia/Tokyo')
|
||||
@@ -316,7 +316,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def test_num_queries_instructor_paced(self):
|
||||
self.fetch_course_info_with_queries(self.instructor_paced_course, 18, 4)
|
||||
self.fetch_course_info_with_queries(self.instructor_paced_course, 21, 4)
|
||||
|
||||
def test_num_queries_self_paced(self):
|
||||
self.fetch_course_info_with_queries(self.self_paced_course, 18, 4)
|
||||
self.fetch_course_info_with_queries(self.self_paced_course, 21, 4)
|
||||
|
||||
@@ -14,7 +14,6 @@ from django.core.urlresolvers import reverse
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
||||
from util.date_utils import get_time_display, DEFAULT_SHORT_DATE_FORMAT
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from openedx.core.djangoapps.credit import api as credit_api
|
||||
@@ -122,7 +121,8 @@ class ProgressPageCreditRequirementsTest(SharedModuleStoreTestCase):
|
||||
response,
|
||||
"{}, you have met the requirements for credit in this course.".format(self.USER_FULL_NAME)
|
||||
)
|
||||
self.assertContains(response, "Completed by {date}".format(date=self._now_formatted_date()))
|
||||
self.assertContains(response, "Completed by {date}")
|
||||
self.assertContains(response, datetime.datetime.now(UTC).strftime('%Y-%m-%d %H'))
|
||||
self.assertNotContains(response, "95%")
|
||||
|
||||
def test_credit_requirements_not_eligible(self):
|
||||
@@ -172,11 +172,3 @@ class ProgressPageCreditRequirementsTest(SharedModuleStoreTestCase):
|
||||
"""Load the progress page for the course the user is enrolled in. """
|
||||
url = reverse("progress", kwargs={"course_id": unicode(self.course.id)})
|
||||
return self.client.get(url)
|
||||
|
||||
def _now_formatted_date(self):
|
||||
"""Retrieve the formatted current date. """
|
||||
return get_time_display(
|
||||
datetime.datetime.now(UTC),
|
||||
DEFAULT_SHORT_DATE_FORMAT,
|
||||
settings.TIME_ZONE
|
||||
)
|
||||
|
||||
@@ -209,6 +209,7 @@ class ViewsTestCase(ModuleStoreTestCase):
|
||||
parent_location=self.chapter.location,
|
||||
due=datetime(2013, 9, 18, 11, 30, 00),
|
||||
display_name='Sequential 1',
|
||||
format='Homework'
|
||||
)
|
||||
self.vertical = ItemFactory.create(
|
||||
category='vertical',
|
||||
@@ -907,33 +908,22 @@ class ViewsTestCase(ModuleStoreTestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_accordion(self):
|
||||
request = RequestFactory().get('foo')
|
||||
request.user = self.user
|
||||
table_of_contents = toc_for_course(
|
||||
request.user,
|
||||
request,
|
||||
self.course,
|
||||
unicode(self.course.get_children()[0].scope_ids.usage_id),
|
||||
None,
|
||||
None
|
||||
)
|
||||
|
||||
# removes newlines and whitespace from the returned view string
|
||||
view = ''.join(render_accordion(request, self.course, table_of_contents['chapters'], 'en').split())
|
||||
# the course id unicode is re-encoded here because the quote function does not accept unicode
|
||||
"""
|
||||
This needs a response_context, which is not included in the render_accordion's main method
|
||||
returning a render_to_string, so we will render via the courseware URL in order to include
|
||||
the needed context
|
||||
"""
|
||||
course_id = quote(unicode(self.course.id).encode("utf-8"))
|
||||
|
||||
self.assertIn(
|
||||
u'href="/courses/{}/courseware/Chapter_1/Sequential_1/"><pclass="accordion-display-name">Sequential1</p>'
|
||||
.format(course_id.decode("utf-8")),
|
||||
view
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
u'href="/courses/{}/courseware/Chapter_1/Sequential_2/"><pclass="accordion-display-name">Sequential2</p>'
|
||||
.format(course_id.decode("utf-8")),
|
||||
view
|
||||
response = self.client.get(
|
||||
reverse('courseware', args=[unicode(course_id)]),
|
||||
follow=True
|
||||
)
|
||||
test_responses = [
|
||||
'<p class="accordion-display-name">Sequential 1 <span class="sr">current section</span></p>',
|
||||
'<p class="accordion-display-name">Sequential 2 </p>'
|
||||
]
|
||||
for test in test_responses:
|
||||
self.assertContains(response, test)
|
||||
|
||||
|
||||
@attr(shard=1)
|
||||
@@ -960,7 +950,8 @@ class BaseDueDateTests(ModuleStoreTestCase):
|
||||
section = ItemFactory.create(
|
||||
category='sequential',
|
||||
parent_location=chapter.location,
|
||||
due=datetime(2013, 9, 18, 11, 30, 00)
|
||||
due=datetime(2013, 9, 18, 11, 30, 00),
|
||||
format='homework'
|
||||
)
|
||||
vertical = ItemFactory.create(category='vertical', parent_location=section.location)
|
||||
ItemFactory.create(category='problem', parent_location=vertical.location)
|
||||
@@ -975,8 +966,7 @@ class BaseDueDateTests(ModuleStoreTestCase):
|
||||
self.user = UserFactory.create()
|
||||
self.assertTrue(self.client.login(username=self.user.username, password='test'))
|
||||
|
||||
self.time_with_tz = "due Sep 18, 2013 at 11:30 UTC"
|
||||
self.time_without_tz = "due Sep 18, 2013 at 11:30"
|
||||
self.time_with_tz = "2013-09-18 11:30:00+00:00"
|
||||
|
||||
def test_backwards_compatability(self):
|
||||
# The test course being used has show_timezone = False in the policy file
|
||||
@@ -985,8 +975,7 @@ class BaseDueDateTests(ModuleStoreTestCase):
|
||||
# remove the timezone.
|
||||
course = self.set_up_course(due_date_display_format=None, show_timezone=False)
|
||||
response = self.get_response(course)
|
||||
self.assertContains(response, self.time_without_tz)
|
||||
self.assertNotContains(response, self.time_with_tz)
|
||||
self.assertContains(response, self.time_with_tz)
|
||||
# Test that show_timezone has been cleared (which means you get the default value of True).
|
||||
self.assertTrue(course.show_timezone)
|
||||
|
||||
@@ -1001,25 +990,11 @@ class BaseDueDateTests(ModuleStoreTestCase):
|
||||
response = self.get_response(course)
|
||||
self.assertContains(response, self.time_with_tz)
|
||||
|
||||
def test_format_plain_text(self):
|
||||
# plain text due date
|
||||
course = self.set_up_course(due_date_display_format="foobar")
|
||||
response = self.get_response(course)
|
||||
self.assertNotContains(response, self.time_with_tz)
|
||||
self.assertContains(response, "due foobar")
|
||||
|
||||
def test_format_date(self):
|
||||
# due date with no time
|
||||
course = self.set_up_course(due_date_display_format=u"%b %d %y")
|
||||
response = self.get_response(course)
|
||||
self.assertNotContains(response, self.time_with_tz)
|
||||
self.assertContains(response, "due Sep 18 13")
|
||||
|
||||
def test_format_hidden(self):
|
||||
# hide due date completely
|
||||
course = self.set_up_course(due_date_display_format=u"")
|
||||
response = self.get_response(course)
|
||||
self.assertNotContains(response, "due ")
|
||||
self.assertContains(response, self.time_with_tz)
|
||||
|
||||
def test_format_invalid(self):
|
||||
# improperly formatted due_date_display_format falls through to default
|
||||
@@ -1049,7 +1024,10 @@ class TestAccordionDueDate(BaseDueDateTests):
|
||||
|
||||
def get_response(self, course):
|
||||
""" Returns the HTML for the accordion """
|
||||
return self.client.get(reverse('courseware', args=[unicode(course.id)]), follow=True)
|
||||
return self.client.get(
|
||||
reverse('courseware', args=[unicode(course.id)]),
|
||||
follow=True
|
||||
)
|
||||
|
||||
|
||||
@attr(shard=1)
|
||||
@@ -1089,14 +1067,17 @@ class StartDateTests(ModuleStoreTestCase):
|
||||
course = self.set_up_course()
|
||||
response = self.get_about_response(course.id)
|
||||
# The start date is set in the set_up_course function above.
|
||||
self.assertContains(response, "2013-SEPTEMBER-16")
|
||||
# This should return in the format '%Y-%m-%dT%H:%M:%S%z'
|
||||
self.assertContains(response, "2013-09-16T07:17:28+0000")
|
||||
|
||||
@patch('util.date_utils.pgettext', fake_pgettext(translations={
|
||||
("abbreviated month name", "Jul"): "JULY",
|
||||
}))
|
||||
@patch('util.date_utils.ugettext', fake_ugettext(translations={
|
||||
"SHORT_DATE_FORMAT": "%Y-%b-%d",
|
||||
}))
|
||||
@patch(
|
||||
'util.date_utils.pgettext',
|
||||
fake_pgettext(translations={("abbreviated month name", "Jul"): "JULY", })
|
||||
)
|
||||
@patch(
|
||||
'util.date_utils.ugettext',
|
||||
fake_ugettext(translations={"SHORT_DATE_FORMAT": "%Y-%b-%d", })
|
||||
)
|
||||
@unittest.skip
|
||||
def test_format_localized_in_xml_course(self):
|
||||
response = self.get_about_response(SlashSeparatedCourseKey('edX', 'toy', 'TT_2012_Fall'))
|
||||
@@ -1345,17 +1326,17 @@ class ProgressPageTests(ModuleStoreTestCase):
|
||||
"""Test that query counts remain the same for self-paced and instructor-paced courses."""
|
||||
SelfPacedConfiguration(enabled=self_paced_enabled).save()
|
||||
self.setup_course(self_paced=self_paced)
|
||||
with self.assertNumQueries(35), check_mongo_calls(4):
|
||||
with self.assertNumQueries(38), check_mongo_calls(4):
|
||||
self._get_progress_page()
|
||||
|
||||
def test_progress_queries(self):
|
||||
self.setup_course()
|
||||
with self.assertNumQueries(35), check_mongo_calls(4):
|
||||
with self.assertNumQueries(38), check_mongo_calls(4):
|
||||
self._get_progress_page()
|
||||
|
||||
# subsequent accesses to the progress page require fewer queries.
|
||||
for _ in range(2):
|
||||
with self.assertNumQueries(21), check_mongo_calls(4):
|
||||
with self.assertNumQueries(24), check_mongo_calls(4):
|
||||
self._get_progress_page()
|
||||
|
||||
@patch(
|
||||
|
||||
@@ -24,7 +24,6 @@ import urllib
|
||||
|
||||
from xblock.fragment import Fragment
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.lib.time_zone_utils import get_user_time_zone
|
||||
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
from shoppingcart.models import CourseRegistrationCode
|
||||
@@ -402,7 +401,6 @@ class CoursewareIndex(View):
|
||||
self.request,
|
||||
self.course,
|
||||
table_of_contents['chapters'],
|
||||
courseware_context['language_preference'],
|
||||
)
|
||||
|
||||
# entrance exam data
|
||||
@@ -499,7 +497,7 @@ class CoursewareIndex(View):
|
||||
raise
|
||||
|
||||
|
||||
def render_accordion(request, course, table_of_contents, language_preference):
|
||||
def render_accordion(request, course, table_of_contents):
|
||||
"""
|
||||
Returns the HTML that renders the navigation for the given course.
|
||||
Expects the table_of_contents to have data on each chapter and section,
|
||||
@@ -511,9 +509,6 @@ def render_accordion(request, course, table_of_contents, language_preference):
|
||||
('course_id', unicode(course.id)),
|
||||
('csrf', csrf(request)['csrf_token']),
|
||||
('due_date_display_format', course.due_date_display_format),
|
||||
('time_zone', request.user.preferences.model.get_value(request.user, "time_zone", None)),
|
||||
('language', language_preference),
|
||||
|
||||
] + TEMPLATE_IMPORTS.items()
|
||||
)
|
||||
return render_to_string('courseware/accordion.html', context)
|
||||
|
||||
Reference in New Issue
Block a user