Merge pull request #31408 from open-craft/agrendalath/fix_site_language

fix: use language specified in SiteConfiguration
This commit is contained in:
Pooja Kulkarni
2022-12-09 11:20:52 -05:00
committed by GitHub
5 changed files with 77 additions and 37 deletions

View File

@@ -501,21 +501,17 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
assert response.data['last_visited_block_id'] == str(self.unit.location)
# Since we are testing an non atomic view in atomic test case, therefore we are expecting error on failures
def api_error_response(self, reverse_args=None, data=None, **kwargs):
def api_atomic_response(self, reverse_args=None, data=None, **kwargs):
"""
Same as api response from MobileAPITestCase but handle views which throw errors
Same as the api_response from MobileAPITestCase, but handles the view as an atomic transaction.
"""
url = self.reverse_url(reverse_args, **kwargs)
try:
with transaction.atomic():
self.url_method(url, data=data, **kwargs)
assert False
except transaction.TransactionManagementError:
assert True
with transaction.atomic():
self.url_method(url, data=data, **kwargs)
def test_invalid_user(self):
self.login_and_enroll()
self.api_error_response(username='no_user')
self.api_atomic_response(username='no_user')
def test_other_user(self):
# login and enroll as the test user
@@ -530,22 +526,22 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
# now login and call the API as the test user
self.login()
self.api_error_response(username=other.username)
self.api_atomic_response(username=other.username)
def test_course_not_found(self):
non_existent_course_id = CourseKey.from_string('a/b/c')
self.init_course_access(course_id=non_existent_course_id)
self.api_error_response(course_id=non_existent_course_id)
self.api_atomic_response(course_id=non_existent_course_id)
def test_unenrolled_user(self):
self.login()
self.unenroll()
self.api_error_response(expected_response_code=None)
self.api_atomic_response(expected_response_code=None)
def test_no_auth(self):
self.logout()
self.api_error_response()
self.api_atomic_response()
class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,

View File

@@ -17,7 +17,6 @@ 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.helpers import set_language_cookie
from openedx.core.djangoapps.site_configuration.helpers import get_value
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
# If django 1.7 or higher is used, the right-side can be updated with new-style codes.
@@ -98,20 +97,10 @@ class DarkLangMiddleware(MiddlewareMixin):
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
set_language_cookie(request, response, language)
def _fuzzy_match(self, lang_code):
"""Returns a fuzzy match for lang_code"""
match = None

View File

@@ -14,7 +14,10 @@ from django.utils.translation import LANGUAGE_SESSION_KEY
from openedx.core.djangoapps.dark_lang.middleware import DarkLangMiddleware
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration
from openedx.core.djangoapps.site_configuration.tests.test_util import (
with_site_configuration,
with_site_configuration_context,
)
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from common.djangoapps.student.tests.factories import UserFactory
@@ -258,16 +261,6 @@ class DarkLangMiddlewareTests(CacheIsolationTestCase):
session[LANGUAGE_SESSION_KEY] = session_language
session.save()
@with_site_configuration(configuration={'LANGUAGE_CODE': 'rel'})
def test_site_configuration_language(self):
# `LANGUAGE_CODE` in site configuration should override session lang
self._set_client_session_language('notrel')
self.client.get('/home')
self.assert_session_lang_equals(
'rel',
self.client.session
)
def test_preview_lang_with_released_language(self):
# Preview lang should always override selection
self._post_set_preview_lang('rel')
@@ -404,3 +397,25 @@ class DarkLangMiddlewareTests(CacheIsolationTestCase):
assert settings.LANGUAGE_COOKIE_NAME in response.cookies
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == ''
assert response['Content-Language'] == site_lang
@with_site_configuration(configuration={'LANGUAGE_CODE': 'es'})
def test_preview_language_ignores_site_configuration(self):
"""
Test that the preview language has a higher priority than the language set in SiteConfiguration.
"""
response = self.client.get('/')
assert response['Content-Language'] == 'es-419'
# Set preview language.
self._post_set_preview_lang('eo')
response = self.client.get('/')
assert response['Content-Language'] == 'eo'
# Reset preview language.
self._post_clear_preview_lang()
response = self.client.get('/')
assert response['Content-Language'] == 'es-419'
# Clean up by making a request to a Site without specific configuration.
with with_site_configuration_context():
self.client.get('/')

View File

@@ -1,8 +1,7 @@
"""
Middleware for Language Preferences
"""
from django.conf import settings
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
@@ -11,6 +10,7 @@ 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 LANGUAGE_HEADER, LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref import helpers as lang_pref_helpers
from openedx.core.djangoapps.site_configuration.helpers import get_value
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
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
@@ -28,6 +28,9 @@ 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.
If you specify the LANGUAGE_CODE in SiteConfiguration, it will have a higher priority than the user's language
preference.
"""
cookie_lang = lang_pref_helpers.get_language_cookie(request)
if cookie_lang:
@@ -54,6 +57,10 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
if LANGUAGE_SESSION_KEY in request.session and request.session[LANGUAGE_SESSION_KEY] != cookie_lang:
del request.session[LANGUAGE_SESSION_KEY]
# Apply language specified in SiteConfiguration, ignoring user preferences.
if language := get_value('LANGUAGE_CODE'):
request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = language
def process_response(self, request, response): # lint-amnesty, pylint: disable=missing-function-docstring
# If the user is logged in, check for their language preference. Also check for real user
# if current user is a masquerading user,

View File

@@ -14,8 +14,13 @@ from django.test.client import Client, RequestFactory
from django.urls import reverse
from django.utils.translation import LANGUAGE_SESSION_KEY
from django.utils.translation.trans_real import parse_accept_lang_header
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION, LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref.middleware import LanguagePreferenceMiddleware
from openedx.core.djangoapps.site_configuration.tests.test_util import (
with_site_configuration,
with_site_configuration_context,
)
from openedx.core.djangoapps.user_api.preferences.api import (
delete_user_preference,
get_user_preference,
@@ -267,3 +272,31 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
mock_is_mobile_request.return_value = True
response = self.middleware.process_response(self.request, response)
response.delete_cookie.assert_called()
@with_site_configuration(configuration={'LANGUAGE_CODE': 'eo'})
@ddt.data(None, 'es', 'en')
def test_site_language_ignores_user_preferences(self, user_preference):
"""
Test that the language set in SiteConfiguration has a higher priority than user preferences.
It also does not create or update user preferences.
"""
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = user_preference
self.middleware.process_request(self.request)
# Do not alter user preferences.
assert get_user_preference(self.user, LANGUAGE_KEY) == user_preference
# Change the request's cookie instead.
assert self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] == 'eo'
# Use an actual call to determine the language of the response.
response = self.client.get('/')
assert get_user_preference(self.user, LANGUAGE_KEY) == user_preference
assert response['Content-Language'] == 'eo'
# `LocaleMiddleware` no longer looks for language in the session since Django 3.2. It checks the cookie instead.
# See: https://docs.djangoproject.com/en/3.2/releases/3.0/#miscellaneous
assert self.client.session.get(LANGUAGE_SESSION_KEY) is None
# Clean up by making a request to a Site without specific configuration.
with with_site_configuration_context():
self.client.get('/')