diff --git a/common/djangoapps/dark_lang/middleware.py b/common/djangoapps/dark_lang/middleware.py index 7a7a6b8868..0f049d3e5e 100644 --- a/common/djangoapps/dark_lang/middleware.py +++ b/common/djangoapps/dark_lang/middleware.py @@ -13,10 +13,13 @@ the SessionMiddleware. from django.conf import settings from dark_lang.models import DarkLangConfig +from openedx.core.djangoapps.user_api.preferences.api import get_user_preference +from lang_pref import LANGUAGE_KEY # TODO re-import this once we're on Django 1.5 or greater. [PLAT-671] # from django.utils.translation.trans_real import parse_accept_lang_header -from django_locale.trans_real import parse_accept_lang_header +# from django.utils.translation import LANGUAGE_SESSION_KEY +from django_locale.trans_real import parse_accept_lang_header, LANGUAGE_SESSION_KEY def dark_parse_accept_lang_header(accept): @@ -124,15 +127,20 @@ class DarkLangMiddleware(object): """ If the request has the get parameter ``preview-lang``, and that language doesn't appear in ``self.released_langs``, - then set the session ``django_language`` to that language. + then set the session LANGUAGE_SESSION_KEY to that language. """ if 'clear-lang' in request.GET: - if 'django_language' in request.session: - del request.session['django_language'] + # Reset user's language to their language preference, if they have one + user_pref = get_user_preference(request.user, LANGUAGE_KEY) + if user_pref: + request.session[LANGUAGE_SESSION_KEY] = user_pref + elif LANGUAGE_SESSION_KEY in request.session: + del request.session[LANGUAGE_SESSION_KEY] + return preview_lang = request.GET.get('preview-lang', None) if not preview_lang: return - request.session['django_language'] = preview_lang + request.session[LANGUAGE_SESSION_KEY] = preview_lang diff --git a/common/djangoapps/dark_lang/tests.py b/common/djangoapps/dark_lang/tests.py index b7210088e9..13519b32eb 100644 --- a/common/djangoapps/dark_lang/tests.py +++ b/common/djangoapps/dark_lang/tests.py @@ -11,6 +11,10 @@ import unittest from dark_lang.middleware import DarkLangMiddleware from dark_lang.models import DarkLangConfig +# TODO PLAT-671 Import from Django 1.8 +# from django.utils.translation import LANGUAGE_SESSION_KEY +from django_locale.trans_real import LANGUAGE_SESSION_KEY +from student.tests.factories import UserFactory UNSET = object() @@ -40,18 +44,18 @@ class DarkLangMiddlewareTests(TestCase): enabled=True ).save() - def process_request(self, django_language=UNSET, accept=UNSET, preview_lang=UNSET, clear_lang=UNSET): + def process_request(self, language_session_key=UNSET, accept=UNSET, preview_lang=UNSET, clear_lang=UNSET): """ Build a request and then process it using the ``DarkLangMiddleware``. Args: - django_language (str): The language code to set in request.session['django_language'] + language_session_key (str): The language code to set in request.session[LANUGAGE_SESSION_KEY] accept (str): The accept header to set in request.META['HTTP_ACCEPT_LANGUAGE'] preview_lang (str): The value to set in request.GET['preview_lang'] clear_lang (str): The value to set in request.GET['clear_lang'] """ session = {} - set_if_set(session, 'django_language', django_language) + set_if_set(session, LANGUAGE_SESSION_KEY, language_session_key) meta = {} set_if_set(meta, 'HTTP_ACCEPT_LANGUAGE', accept) @@ -64,7 +68,8 @@ class DarkLangMiddlewareTests(TestCase): spec=HttpRequest, session=session, META=meta, - GET=get + GET=get, + user=UserFactory() ) self.assertIsNone(DarkLangMiddleware().process_request(request)) return request @@ -231,11 +236,11 @@ class DarkLangMiddlewareTests(TestCase): def assertSessionLangEquals(self, value, request): """ - Assert that the 'django_language' set in request.session is equal to value + Assert that the LANGUAGE_SESSION_KEY set in request.session is equal to value """ self.assertEquals( value, - request.session.get('django_language', UNSET) + request.session.get(LANGUAGE_SESSION_KEY, UNSET) ) def test_preview_lang_with_released_language(self): @@ -247,7 +252,7 @@ class DarkLangMiddlewareTests(TestCase): self.assertSessionLangEquals( 'rel', - self.process_request(preview_lang='rel', django_language='notrel') + self.process_request(preview_lang='rel', language_session_key='notrel') ) def test_preview_lang_with_dark_language(self): @@ -258,7 +263,7 @@ class DarkLangMiddlewareTests(TestCase): self.assertSessionLangEquals( 'unrel', - self.process_request(preview_lang='unrel', django_language='notrel') + self.process_request(preview_lang='unrel', language_session_key='notrel') ) def test_clear_lang(self): @@ -269,12 +274,12 @@ class DarkLangMiddlewareTests(TestCase): self.assertSessionLangEquals( UNSET, - self.process_request(clear_lang=True, django_language='rel') + self.process_request(clear_lang=True, language_session_key='rel') ) self.assertSessionLangEquals( UNSET, - self.process_request(clear_lang=True, django_language='unrel') + self.process_request(clear_lang=True, language_session_key='unrel') ) def test_disabled(self): @@ -287,17 +292,17 @@ class DarkLangMiddlewareTests(TestCase): self.assertSessionLangEquals( 'rel', - self.process_request(clear_lang=True, django_language='rel') + self.process_request(clear_lang=True, language_session_key='rel') ) self.assertSessionLangEquals( 'unrel', - self.process_request(clear_lang=True, django_language='unrel') + self.process_request(clear_lang=True, language_session_key='unrel') ) self.assertSessionLangEquals( 'rel', - self.process_request(preview_lang='unrel', django_language='rel') + self.process_request(preview_lang='unrel', language_session_key='rel') ) def test_accept_chinese_language_codes(self): diff --git a/common/djangoapps/lang_pref/middleware.py b/common/djangoapps/lang_pref/middleware.py index a7df9803c4..1631a871a0 100644 --- a/common/djangoapps/lang_pref/middleware.py +++ b/common/djangoapps/lang_pref/middleware.py @@ -4,6 +4,9 @@ Middleware for Language Preferences from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from lang_pref import LANGUAGE_KEY +# TODO PLAT-671 Import from Django 1.8 +# from django.utils.translation import LANGUAGE_SESSION_KEY +from django_locale.trans_real import LANGUAGE_SESSION_KEY class LanguagePreferenceMiddleware(object): @@ -16,10 +19,12 @@ class LanguagePreferenceMiddleware(object): def process_request(self, request): """ - If a user's UserPreference contains a language preference and there is - no language set on the session (i.e. from dark language overrides), use the user's preference. + If a user's UserPreference contains a language preference, use the user's preference. """ - if request.user.is_authenticated() and 'django_language' not in request.session: + # If the user is logged in, check for their language preference + if request.user.is_authenticated(): + # Get the user's language preference user_pref = get_user_preference(request.user, LANGUAGE_KEY) + # Set it to the LANGUAGE_SESSION_KEY (Django-specific session setting governing language pref) if user_pref: - request.session['django_language'] = user_pref + request.session[LANGUAGE_SESSION_KEY] = user_pref diff --git a/common/djangoapps/lang_pref/tests/test_middleware.py b/common/djangoapps/lang_pref/tests/test_middleware.py index ccc8b69a48..46934db6e1 100644 --- a/common/djangoapps/lang_pref/tests/test_middleware.py +++ b/common/djangoapps/lang_pref/tests/test_middleware.py @@ -1,6 +1,9 @@ from django.test import TestCase from django.test.client import RequestFactory from django.contrib.sessions.middleware import SessionMiddleware +# TODO PLAT-671 Import from Django 1.8 +# from django.utils.translation import LANGUAGE_SESSION_KEY +from django_locale.trans_real import LANGUAGE_SESSION_KEY from lang_pref.middleware import LanguagePreferenceMiddleware from openedx.core.djangoapps.user_api.preferences.api import set_user_preference @@ -25,19 +28,23 @@ class TestUserPreferenceMiddleware(TestCase): def test_no_language_set_in_session_or_prefs(self): # nothing set in the session or the prefs self.middleware.process_request(self.request) - self.assertNotIn('django_language', self.request.session) + self.assertNotIn(LANGUAGE_SESSION_KEY, self.request.session) def test_language_in_user_prefs(self): # language set in the user preferences and not the session set_user_preference(self.user, LANGUAGE_KEY, 'eo') self.middleware.process_request(self.request) - self.assertEquals(self.request.session['django_language'], 'eo') + self.assertEquals(self.request.session[LANGUAGE_SESSION_KEY], 'eo') def test_language_in_session(self): # language set in both the user preferences and session, - # session should get precedence - self.request.session['django_language'] = 'en' + # preference should get precedence. The session will hold the last value, + # which is probably the user's last preference. Look up the updated preference. + + # Dark lang middleware should run after this middleware, so it can + # set a session language as an override of the user's preference. + self.request.session[LANGUAGE_SESSION_KEY] = 'en' set_user_preference(self.user, LANGUAGE_KEY, 'eo') self.middleware.process_request(self.request) - self.assertEquals(self.request.session['django_language'], 'en') + self.assertEquals(self.request.session[LANGUAGE_SESSION_KEY], 'eo') diff --git a/lms/envs/common.py b/lms/envs/common.py index 9847eadd1f..7a4253d39f 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1142,16 +1142,20 @@ MIDDLEWARE_CLASSES = ( 'splash.middleware.SplashMiddleware', - # Allows us to dark-launch particular languages - 'dark_lang.middleware.DarkLangMiddleware', + 'geoinfo.middleware.CountryMiddleware', 'embargo.middleware.EmbargoMiddleware', # Allows us to set user preferences - # should be after DarkLangMiddleware 'lang_pref.middleware.LanguagePreferenceMiddleware', - # Detects user-requested locale from 'accept-language' header in http request + # Allows us to dark-launch particular languages. + # Must be after LangPrefMiddleware, so ?preview-lang query params can override + # user's language preference. ?clear-lang resets to user's language preference. + 'dark_lang.middleware.DarkLangMiddleware', + + # Detects user-requested locale from 'accept-language' header in http request. + # Must be after DarkLangMiddleware. # TODO: Re-import the Django version once we upgrade to Django 1.8 [PLAT-671] # 'django.middleware.locale.LocaleMiddleware', 'django_locale.middleware.LocaleMiddleware',