diff --git a/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1.py b/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1.py new file mode 100644 index 000000000..6d416e7e1 --- /dev/null +++ b/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1.py @@ -0,0 +1,9 @@ +""" +LanguagePreferenceMiddleware Backend. +""" +from openedx.core.djangoapps.lang_pref.middleware import LanguagePreferenceMiddleware # pylint: disable=import-error + + +def get_language_preference_middleware(): + """Backend to get the LanguagePreferenceMiddleware from openedx.""" + return LanguagePreferenceMiddleware diff --git a/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1_test.py b/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1_test.py new file mode 100644 index 000000000..bd883ab3e --- /dev/null +++ b/eox_core/edxapp_wrapper/backends/lang_pref_middleware_p_v1_test.py @@ -0,0 +1,18 @@ +""" +LanguagePreferenceMiddleware Backend. +""" + + +def get_language_preference_middleware(): + """Backend to get the LanguagePreferenceMiddleware from openedx.""" + class LanguagePreferenceMiddleware: + """LanguagePreferenceMiddleware Backend Mock.""" + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + # Simulate the behavior of LanguagePreferenceMiddleware + # For example, set a language preference in the request + request.LANGUAGE_CODE = 'en' + return self.get_response(request) + return LanguagePreferenceMiddleware diff --git a/eox_core/edxapp_wrapper/language_preference.py b/eox_core/edxapp_wrapper/language_preference.py new file mode 100644 index 000000000..8f9f32382 --- /dev/null +++ b/eox_core/edxapp_wrapper/language_preference.py @@ -0,0 +1,11 @@ +""" Backend abstraction. """ +from importlib import import_module + +from django.conf import settings + + +def get_language_preference_middleware(*args, **kwargs): + """ Get LanguagePreferenceMiddleware. """ + backend_function = settings.EOX_CORE_LANG_PREF_BACKEND + backend = import_module(backend_function) + return backend.get_language_preference_middleware(*args, **kwargs) diff --git a/eox_core/middleware.py b/eox_core/middleware.py index dbca630b6..fa1d13639 100644 --- a/eox_core/middleware.py +++ b/eox_core/middleware.py @@ -17,13 +17,14 @@ from django.db import IntegrityError from django.db.models.signals import post_save from django.dispatch import receiver -from django.http import Http404, HttpResponseRedirect +from django.http import Http404, HttpResponseRedirect, parse_cookie from django.urls import reverse from django.utils.deprecation import MiddlewareMixin from requests.exceptions import HTTPError from social_core.exceptions import AuthAlreadyAssociated, AuthFailed, AuthUnreachableProvider from eox_core.edxapp_wrapper.configuration_helpers import get_configuration_helper +from eox_core.edxapp_wrapper.language_preference import get_language_preference_middleware from eox_core.edxapp_wrapper.third_party_auth import get_tpa_exception_middleware from eox_core.models import Redirection from eox_core.utils import cache, fasthash @@ -42,6 +43,7 @@ class EoxTenantAuthException: configuration_helper = get_configuration_helper() # pylint: disable=invalid-name ExceptionMiddleware = get_tpa_exception_middleware() +LanguagePreferenceMiddleware = get_language_preference_middleware() class PathRedirectionMiddleware(MiddlewareMixin): @@ -284,3 +286,24 @@ def process_exception(self, request, exception): return super().process_exception(request, new_exception) return super().process_exception(request, exception) + + +class UserLanguagePreferenceMiddleware(LanguagePreferenceMiddleware): + """This Middleware allows the user set the language preference for the site, avoiding the default LANGUAGE_CODE. + + The previous behavior was modified here + https://github.com/openedx/edx-platform/blob/open-release/palm.master/openedx/core/djangoapps/lang_pref/middleware.py#L61-L62 + """ + 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. + """ + original_user_language_cookie = parse_cookie(request.META.get("HTTP_COOKIE", "")).get( + settings.LANGUAGE_COOKIE_NAME + ) + + if original_user_language_cookie: + request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = original_user_language_cookie + + return self.get_response(request) diff --git a/eox_core/settings/common.py b/eox_core/settings/common.py index 96624ad24..616631261 100644 --- a/eox_core/settings/common.py +++ b/eox_core/settings/common.py @@ -49,6 +49,7 @@ def plugin_settings(settings): settings.EOX_CORE_BEARER_AUTHENTICATION = 'eox_core.edxapp_wrapper.backends.bearer_authentication_j_v1' settings.EOX_CORE_ASYNC_TASKS = [] settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND = 'eox_core.edxapp_wrapper.backends.third_party_auth_l_v1' + settings.EOX_CORE_LANG_PREF_BACKEND = 'eox_core.edxapp_wrapper.backends.lang_pref_middleware_p_v1' if settings.EOX_CORE_USER_ENABLE_MULTI_TENANCY: settings.EOX_CORE_USER_ORIGIN_SITE_SOURCES = [ diff --git a/eox_core/settings/production.py b/eox_core/settings/production.py index 21de41eed..7afb65011 100644 --- a/eox_core/settings/production.py +++ b/eox_core/settings/production.py @@ -123,6 +123,11 @@ def plugin_settings(settings): # pylint: disable=function-redefined 'eox_core.middleware.TPAExceptionMiddleware' ] + settings.MIDDLEWARE.insert( + settings.MIDDLEWARE.index("openedx.core.djangoapps.lang_pref.middleware.LanguagePreferenceMiddleware") + 1, + "eox_core.middleware.UserLanguagePreferenceMiddleware", + ) + # Sentry Integration sentry_integration_dsn = getattr(settings, 'ENV_TOKENS', {}).get( 'EOX_CORE_SENTRY_INTEGRATION_DSN', diff --git a/eox_core/settings/test.py b/eox_core/settings/test.py index 82b19801e..0964aa86c 100644 --- a/eox_core/settings/test.py +++ b/eox_core/settings/test.py @@ -33,6 +33,7 @@ def plugin_settings(settings): # pylint: disable=function-redefined settings.EOX_CORE_USER_UPDATE_SAFE_FIELDS = ["is_active", "password", "fullname"] settings.EOX_CORE_BEARER_AUTHENTICATION = 'eox_core.edxapp_wrapper.backends.bearer_authentication_j_v1_test' settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND = 'eox_core.edxapp_wrapper.backends.third_party_auth_l_v1' + settings.EOX_CORE_LANG_PREF_BACKEND = 'eox_core.edxapp_wrapper.backends.lang_pref_middleware_p_v1_test' SETTINGS = SettingsClass() diff --git a/eox_core/tests/test_middleware.py b/eox_core/tests/test_middleware.py index eb4666baf..70743cd66 100644 --- a/eox_core/tests/test_middleware.py +++ b/eox_core/tests/test_middleware.py @@ -3,11 +3,12 @@ Test module for the custom Middlewares """ import mock +from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.http import Http404 from django.test import RequestFactory, TestCase -from eox_core.middleware import PathRedirectionMiddleware, RedirectionsMiddleware +from eox_core.middleware import PathRedirectionMiddleware, RedirectionsMiddleware, UserLanguagePreferenceMiddleware from eox_core.models import Redirection @@ -165,3 +166,36 @@ def test_redirection(self, redirection_get_mock): result = self.middleware_instance.process_request(request) self.assertIsNotNone(result) + + +class UserLanguagePreferenceMiddlewareTestCase(TestCase): + """ + Test the UserLanguagePreferenceMiddleware. + """ + def setUp(self): + self.factory = RequestFactory() + self.middleware = UserLanguagePreferenceMiddleware(get_response=lambda req: None) + + def test_process_request_with_language_cookie(self): + """ + Test if the language cookie is set correctly in the request. + """ + language_code = 'fr' + request = self.factory.get('/') + request.META['HTTP_COOKIE'] = f'{settings.LANGUAGE_COOKIE_NAME}={language_code}' + self.middleware(request) + + # Check if the language cookie was set correctly in the request + self.assertIn(settings.LANGUAGE_COOKIE_NAME, request.COOKIES) + self.assertEqual(request.COOKIES[settings.LANGUAGE_COOKIE_NAME], language_code) + + def test_process_request_without_language_cookie(self): + """ + Test if the language cookie is not set in the request. + """ + + request = self.factory.get('/') + self.middleware(request) + + # Check that the language cookie is not set in the request + self.assertNotIn(settings.LANGUAGE_COOKIE_NAME, request.COOKIES)