Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions lms/djangoapps/mobile_api/users/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,21 +501,17 @@ def test_success_v1(self):
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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not seem to be related, but it stopped throwing the TransactionManagementError once we added the site_configuration.get_value() call to the language preferences middleware.

This was not the case before because this feature was gated behind DarkLangConfig, which is disabled in this test. This gating does not make much sense, as this feature does not depend on DarkLang.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find @Agrendalath!

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
Expand All @@ -530,22 +526,22 @@ def test_other_user(self):

# 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,
Expand Down
11 changes: 0 additions & 11 deletions openedx/core/djangoapps/dark_lang/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
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.
Expand Down Expand Up @@ -98,20 +97,10 @@ 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
set_language_cookie(request, response, language)

def _fuzzy_match(self, lang_code):
"""Returns a fuzzy match for lang_code"""
match = None
Expand Down
37 changes: 26 additions & 11 deletions openedx/core/djangoapps/dark_lang/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

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

Expand Down Expand Up @@ -258,16 +261,6 @@ def _set_client_session_language(self, session_language):
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')
Expand Down Expand Up @@ -404,3 +397,25 @@ def test_language_cookie_is_set(self):
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('/')
11 changes: 9 additions & 2 deletions openedx/core/djangoapps/lang_pref/middleware.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -11,6 +10,7 @@
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
Expand All @@ -28,6 +28,9 @@ def process_request(self, request):
"""
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:
Expand All @@ -54,6 +57,10 @@ def process_request(self, request):
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,
Expand Down
33 changes: 33 additions & 0 deletions openedx/core/djangoapps/lang_pref/tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@
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,
Expand Down Expand Up @@ -267,3 +272,31 @@ def test_remove_lang_cookie_for_mobile_app(self, mock_get_user_preference, mock_
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('/')