fix: use cookies for storing language instead of session
- Fixed LANGUAGE_COOKIE settings name to LANGUAGE_COOKIE_NAME beacuse later is recognised by django - Added test to verify cookies use in dark lang middleware - Fixing Django 3.0 tests
This commit is contained in:
@@ -1080,7 +1080,7 @@ TIME_ZONE = 'UTC'
|
||||
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGES_BIDI = lms.envs.common.LANGUAGES_BIDI
|
||||
|
||||
LANGUAGE_COOKIE = lms.envs.common.LANGUAGE_COOKIE
|
||||
LANGUAGE_COOKIE_NAME = lms.envs.common.LANGUAGE_COOKIE_NAME
|
||||
|
||||
LANGUAGES = lms.envs.common.LANGUAGES
|
||||
LANGUAGE_DICT = dict(LANGUAGES)
|
||||
|
||||
@@ -600,3 +600,5 @@ COURSE_OLX_VALIDATION_IGNORE_LIST = ENV_TOKENS.get(
|
||||
|
||||
################# show account activate cta after register ########################
|
||||
SHOW_ACCOUNT_ACTIVATION_CTA = ENV_TOKENS.get('SHOW_ACCOUNT_ACTIVATION_CTA', SHOW_ACCOUNT_ACTIVATION_CTA)
|
||||
|
||||
LANGUAGE_COOKIE_NAME = ENV_TOKENS.get('LANGUAGE_COOKIE', None) or ENV_TOKENS.get('LANGUAGE_COOKIE_NAME')
|
||||
|
||||
@@ -647,12 +647,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
|
||||
)
|
||||
|
||||
user_language = 'fr'
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE] = user_language
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = user_language
|
||||
response = self.client.get(test_url)
|
||||
self.assertContains(response, '<html class="no-js" lang="fr">')
|
||||
|
||||
user_language = 'ar'
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE] = user_language
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = user_language
|
||||
response = self.client.get(test_url)
|
||||
self.assertContains(response, '<html class="no-js" lang="ar">')
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ class TestStaffMasqueradeAsSpecificStudent(StaffMasqueradeTestCase, ProblemSubmi
|
||||
expected_language_code: string indicating a language code
|
||||
"""
|
||||
assert get_user_preference(user, LANGUAGE_KEY) == expected_language_code
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE].value == expected_language_code
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value == expected_language_code
|
||||
|
||||
@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True)
|
||||
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
|
||||
|
||||
@@ -730,7 +730,7 @@ FEATURES = {
|
||||
# .. toggle_description: When set to True, language selector will be visible in the footer.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2017-05-25
|
||||
# .. toggle_warnings: LANGUAGE_COOKIE is required to use footer-language-selector, set it if it has not been set.
|
||||
# .. toggle_warnings: LANGUAGE_COOKIE_NAME is required to use footer-language-selector, set it if it has not been set.
|
||||
# .. toggle_tickets: https://github.com/edx/edx-platform/pull/15133
|
||||
'SHOW_FOOTER_LANGUAGE_SELECTOR': False,
|
||||
|
||||
@@ -1708,7 +1708,7 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
# these languages display right to left
|
||||
LANGUAGES_BIDI = ("he", "ar", "fa", "ur", "fa-ir", "rtl")
|
||||
|
||||
LANGUAGE_COOKIE = "openedx-language-preference"
|
||||
LANGUAGE_COOKIE_NAME = "openedx-language-preference"
|
||||
|
||||
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
|
||||
LANGUAGES = [
|
||||
|
||||
@@ -294,6 +294,8 @@ TIME_ZONE = ENV_TOKENS.get('CELERY_TIMEZONE', CELERY_TIMEZONE)
|
||||
# Translation overrides
|
||||
LANGUAGE_DICT = dict(LANGUAGES)
|
||||
|
||||
LANGUAGE_COOKIE_NAME = ENV_TOKENS.get('LANGUAGE_COOKIE', None) or ENV_TOKENS.get('LANGUAGE_COOKIE_NAME')
|
||||
|
||||
# Additional installed apps
|
||||
for app in ENV_TOKENS.get('ADDL_INSTALLED_APPS', []):
|
||||
INSTALLED_APPS.append(app)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Language-selection widget for the footer.
|
||||
##
|
||||
## Requires settings.LANGUAGE_COOKIE.
|
||||
## Requires settings.LANGUAGE_COOKIE_NAME.
|
||||
<%page expression_filter="h"/>
|
||||
<%!
|
||||
from babel import Locale
|
||||
@@ -11,9 +11,9 @@
|
||||
from openedx.core.djangoapps.lang_pref.api import released_languages
|
||||
from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
|
||||
# Make sure LANGUAGE_COOKIE is present.
|
||||
if not settings.LANGUAGE_COOKIE:
|
||||
raise ValueError('settings.LANGUAGE_COOKIE is required to use footer-language-selector.')
|
||||
# Make sure LANGUAGE_COOKIE_NAME is present.
|
||||
if not settings.LANGUAGE_COOKIE_NAME:
|
||||
raise ValueError('settings.LANGUAGE_COOKIE_NAME is required to use footer-language-selector.')
|
||||
%>
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
},
|
||||
|
||||
setLanguageCookie: function(value, callback) {
|
||||
var cookie = '${settings.LANGUAGE_COOKIE | n, js_escaped_string}=' + value + ';path=/';
|
||||
var cookie = '${settings.LANGUAGE_COOKIE_NAME | n, js_escaped_string}=' + value + ';path=/';
|
||||
|
||||
<% session_cookie_domain = static.get_value('SESSION_COOKIE_DOMAIN', settings.SESSION_COOKIE_DOMAIN) %>
|
||||
% if session_cookie_domain:
|
||||
|
||||
@@ -16,6 +16,7 @@ from django.utils.deprecation import MiddlewareMixin
|
||||
|
||||
from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION
|
||||
from openedx.core.djangoapps.site_configuration.helpers import get_value
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
|
||||
@@ -91,16 +92,31 @@ class DarkLangMiddleware(MiddlewareMixin):
|
||||
return
|
||||
|
||||
self._clean_accept_headers(request)
|
||||
self._set_site_or_microsite_language(request)
|
||||
self._activate_preview_language(request)
|
||||
|
||||
def _set_site_or_microsite_language(self, request):
|
||||
def process_response(self, request, response):
|
||||
"""
|
||||
Apply user's dark lang preference as a cookie for future requests.
|
||||
"""
|
||||
if DarkLangConfig.current().enabled:
|
||||
self._set_site_or_microsite_language(request, response)
|
||||
self._activate_preview_language(request, response)
|
||||
|
||||
return response
|
||||
|
||||
def _set_site_or_microsite_language(self, request, response):
|
||||
"""
|
||||
Apply language specified in site configuration.
|
||||
"""
|
||||
language = get_value('LANGUAGE_CODE', None)
|
||||
if language:
|
||||
request.session[LANGUAGE_SESSION_KEY] = language
|
||||
response.set_cookie(
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
value=language,
|
||||
domain=settings.SHARED_COOKIE_DOMAIN,
|
||||
max_age=COOKIE_DURATION,
|
||||
secure=request.is_secure()
|
||||
)
|
||||
|
||||
def _fuzzy_match(self, lang_code):
|
||||
"""Returns a fuzzy match for lang_code"""
|
||||
@@ -142,7 +158,7 @@ class DarkLangMiddleware(MiddlewareMixin):
|
||||
|
||||
request.META['HTTP_ACCEPT_LANGUAGE'] = new_accept
|
||||
|
||||
def _activate_preview_language(self, request):
|
||||
def _activate_preview_language(self, request, response):
|
||||
"""
|
||||
Check the user's dark language setting in the session and apply it
|
||||
"""
|
||||
@@ -158,3 +174,10 @@ class DarkLangMiddleware(MiddlewareMixin):
|
||||
|
||||
# Set the session key to the requested preview lang
|
||||
request.session[LANGUAGE_SESSION_KEY] = preview_lang
|
||||
response.set_cookie(
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
value=preview_lang,
|
||||
domain=settings.SHARED_COOKIE_DOMAIN,
|
||||
max_age=COOKIE_DURATION,
|
||||
secure=request.is_secure()
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import unittest
|
||||
from unittest.mock import Mock
|
||||
|
||||
import ddt
|
||||
from django.conf import settings
|
||||
from django.http import HttpRequest
|
||||
from django.test.client import Client
|
||||
from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||
@@ -368,3 +369,38 @@ class DarkLangMiddlewareTests(CacheIsolationTestCase):
|
||||
'zh-cn;q=1.0, zh-tw;q=0.5, zh-hk;q=0.3',
|
||||
self.process_middleware_request(accept='zh-Hans;q=1.0, zh-Hant-TW;q=0.5, zh-HK;q=0.3')
|
||||
)
|
||||
|
||||
def test_language_cookie_is_set(self):
|
||||
site_lang = settings.LANGUAGE_CODE
|
||||
url = '/dashboard'
|
||||
|
||||
response = self.client.get(url)
|
||||
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == ''
|
||||
assert response['Content-Language'] == site_lang
|
||||
|
||||
# Set preview language
|
||||
self._post_set_preview_lang("es-419")
|
||||
|
||||
# Check if view has cookies and language set to desired preview language
|
||||
response = self.client.get(url)
|
||||
assert settings.LANGUAGE_COOKIE_NAME in response.cookies
|
||||
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == 'es-419'
|
||||
assert response['Content-Language'] == 'es-419'
|
||||
|
||||
# Change preview language
|
||||
self._post_set_preview_lang("eo")
|
||||
|
||||
# Check if view has cookies and language set to desired preview language
|
||||
response = self.client.get(url)
|
||||
assert settings.LANGUAGE_COOKIE_NAME in response.cookies
|
||||
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == 'eo'
|
||||
assert response['Content-Language'] == 'eo'
|
||||
|
||||
# Reset preview language
|
||||
self._post_clear_preview_lang()
|
||||
|
||||
# Check if view has cookies and language set to default language
|
||||
response = self.client.get(url)
|
||||
assert settings.LANGUAGE_COOKIE_NAME in response.cookies
|
||||
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == ''
|
||||
assert response['Content-Language'] == site_lang
|
||||
|
||||
@@ -8,6 +8,8 @@ from django.utils.deprecation import MiddlewareMixin
|
||||
from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||
from django.utils.translation.trans_real import parse_accept_lang_header
|
||||
|
||||
from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION, LANGUAGE_HEADER, LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.user_api.errors import UserAPIInternalError, UserAPIRequestError
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, set_user_preference
|
||||
@@ -27,9 +29,12 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
|
||||
If a user's UserPreference contains a language preference, use the user's preference.
|
||||
Save the current language preference cookie as the user's preferred language.
|
||||
"""
|
||||
cookie_lang = request.COOKIES.get(settings.LANGUAGE_COOKIE, None)
|
||||
cookie_lang = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME, None)
|
||||
if cookie_lang:
|
||||
if request.user.is_authenticated:
|
||||
# DarkLangMiddleware will take care of this so don't change anything
|
||||
if DarkLangConfig.current().enabled and get_user_preference(request.user, DARK_LANGUAGE_KEY):
|
||||
return
|
||||
set_user_preference(request.user, LANGUAGE_KEY, cookie_lang)
|
||||
else:
|
||||
request._anonymous_user_cookie_lang = cookie_lang # lint-amnesty, pylint: disable=protected-access
|
||||
@@ -58,6 +63,11 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
|
||||
current_user = getattr(request.user, 'real_user', request.user)
|
||||
|
||||
if current_user and current_user.is_authenticated:
|
||||
|
||||
# DarkLangMiddleware has already set this cookie
|
||||
if DarkLangConfig.current().enabled and get_user_preference(current_user, DARK_LANGUAGE_KEY):
|
||||
return response
|
||||
|
||||
anonymous_cookie_lang = getattr(request, '_anonymous_user_cookie_lang', None)
|
||||
if anonymous_cookie_lang:
|
||||
user_pref = anonymous_cookie_lang
|
||||
@@ -70,19 +80,19 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
|
||||
# If we can't find the user preferences, then don't modify the cookie
|
||||
pass
|
||||
|
||||
# If set, set the user_pref in the LANGUAGE_COOKIE
|
||||
# If set, set the user_pref in the LANGUAGE_COOKIE_NAME
|
||||
if user_pref and not is_request_from_mobile_app(request):
|
||||
response.set_cookie(
|
||||
settings.LANGUAGE_COOKIE,
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
value=user_pref,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
domain=settings.SHARED_COOKIE_DOMAIN,
|
||||
max_age=COOKIE_DURATION,
|
||||
secure=request.is_secure()
|
||||
)
|
||||
else:
|
||||
response.delete_cookie(
|
||||
settings.LANGUAGE_COOKIE,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
domain=settings.SHARED_COOKIE_DOMAIN
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@@ -57,7 +57,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
@ddt.data(None, 'es', 'en')
|
||||
def test_preference_setting_changes_cookie(self, lang_pref_out):
|
||||
"""
|
||||
Test that the LANGUAGE_COOKIE is always set to the user's current language preferences
|
||||
Test that the LANGUAGE_COOKIE_NAME is always set to the user's current language preferences
|
||||
at the end of the request, with an expiry that's the same as the users current session cookie.
|
||||
"""
|
||||
if lang_pref_out:
|
||||
@@ -70,7 +70,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
|
||||
if lang_pref_out:
|
||||
response.set_cookie.assert_called_with(
|
||||
settings.LANGUAGE_COOKIE,
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
value=lang_pref_out,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
max_age=COOKIE_DURATION,
|
||||
@@ -78,20 +78,20 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
)
|
||||
else:
|
||||
response.delete_cookie.assert_called_with(
|
||||
settings.LANGUAGE_COOKIE,
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
)
|
||||
|
||||
assert LANGUAGE_SESSION_KEY not in self.request.session
|
||||
|
||||
@ddt.data(*itertools.product(
|
||||
(None, 'eo', 'es'), # LANGUAGE_COOKIE
|
||||
(None, 'eo', 'es'), # LANGUAGE_COOKIE_NAME
|
||||
(None, 'es', 'en'), # Language Preference In
|
||||
))
|
||||
@ddt.unpack
|
||||
@mock.patch('openedx.core.djangoapps.lang_pref.middleware.set_user_preference')
|
||||
def test_preference_cookie_changes_setting(self, lang_cookie, lang_pref_in, mock_set_user_preference):
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE] = lang_cookie
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = lang_cookie
|
||||
|
||||
if lang_pref_in:
|
||||
set_user_preference(self.user, LANGUAGE_KEY, lang_pref_in)
|
||||
@@ -109,7 +109,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
(logged_in, ) + test_def
|
||||
for logged_in in (True, False)
|
||||
for test_def in [
|
||||
# (LANGUAGE_COOKIE, LANGUAGE_SESSION_KEY, Accept-Language In,
|
||||
# (LANGUAGE_COOKIE_NAME, LANGUAGE_SESSION_KEY, Accept-Language In,
|
||||
# Accept-Language Out, Session Lang Out)
|
||||
(None, None, None, None, None),
|
||||
(None, 'eo', None, None, 'eo'),
|
||||
@@ -132,7 +132,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
if not logged_in:
|
||||
self.request.user = self.anonymous_user
|
||||
if lang_cookie:
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE] = lang_cookie
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = lang_cookie
|
||||
if lang_session_in:
|
||||
self.request.session[LANGUAGE_SESSION_KEY] = lang_session_in
|
||||
if accept_lang_in:
|
||||
@@ -159,16 +159,16 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
@ddt.data(None, 'es', 'en')
|
||||
def test_logout_preserves_cookie(self, lang_cookie):
|
||||
if lang_cookie:
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE] = lang_cookie
|
||||
elif settings.LANGUAGE_COOKIE in self.client.cookies:
|
||||
del self.client.cookies[settings.LANGUAGE_COOKIE]
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = lang_cookie
|
||||
elif settings.LANGUAGE_COOKIE_NAME in self.client.cookies:
|
||||
del self.client.cookies[settings.LANGUAGE_COOKIE_NAME]
|
||||
# Use an actual call to the logout endpoint, because the logout function
|
||||
# explicitly clears all cookies
|
||||
self.client.get(reverse('logout'))
|
||||
if lang_cookie:
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE].value == lang_cookie
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value == lang_cookie
|
||||
else:
|
||||
assert settings.LANGUAGE_COOKIE not in self.client.cookies
|
||||
assert settings.LANGUAGE_COOKIE_NAME not in self.client.cookies
|
||||
|
||||
@ddt.data(
|
||||
(None, None),
|
||||
@@ -179,9 +179,9 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
@ddt.unpack
|
||||
def test_login_captures_lang_pref(self, lang_cookie, expected_lang):
|
||||
if lang_cookie:
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE] = lang_cookie
|
||||
elif settings.LANGUAGE_COOKIE in self.client.cookies:
|
||||
del self.client.cookies[settings.LANGUAGE_COOKIE]
|
||||
self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = lang_cookie
|
||||
elif settings.LANGUAGE_COOKIE_NAME in self.client.cookies:
|
||||
del self.client.cookies[settings.LANGUAGE_COOKIE_NAME]
|
||||
|
||||
# Use an actual call to the login endpoint, to validate that the middleware
|
||||
# stack does the right thing
|
||||
@@ -199,11 +199,11 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
if lang_cookie:
|
||||
assert response['Content-Language'] == expected_lang
|
||||
assert get_user_preference(self.user, LANGUAGE_KEY) == lang_cookie
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE].value == lang_cookie
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value == lang_cookie
|
||||
else:
|
||||
assert response['Content-Language'] == 'en'
|
||||
assert get_user_preference(self.user, LANGUAGE_KEY) is None
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE].value == ''
|
||||
assert self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value == ''
|
||||
|
||||
def test_process_response_no_user_noop(self):
|
||||
del self.request.user
|
||||
@@ -215,7 +215,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
assert response.mock_calls == []
|
||||
|
||||
def test_preference_update_noop(self):
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE] = 'es'
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = 'es'
|
||||
|
||||
# No preference yet, should write to the database
|
||||
|
||||
@@ -242,7 +242,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
|
||||
# Cookie changed, should write to the database again
|
||||
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE] = 'en'
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = 'en'
|
||||
self.middleware.process_request(self.request)
|
||||
assert get_user_preference(self.user, LANGUAGE_KEY) == 'en'
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def update_session_language(request):
|
||||
if request.session.get(LANGUAGE_SESSION_KEY, None) != language:
|
||||
request.session[LANGUAGE_SESSION_KEY] = str(language)
|
||||
response.set_cookie(
|
||||
settings.LANGUAGE_COOKIE,
|
||||
settings.LANGUAGE_COOKIE_NAME,
|
||||
language,
|
||||
domain=settings.SHARED_COOKIE_DOMAIN,
|
||||
max_age=COOKIE_DURATION,
|
||||
|
||||
Reference in New Issue
Block a user