Allow changing of language preference from profile page
This commit is contained in:
81
common/djangoapps/lang_pref/api.py
Normal file
81
common/djangoapps/lang_pref/api.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Python API for language and translation management. """
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import get_language
|
||||
from dark_lang.models import DarkLangConfig
|
||||
|
||||
|
||||
# Named tuples can be referenced using object-like variable
|
||||
# deferencing, making the use of tuples more readable by
|
||||
# eliminating the need to see the context of the tuple packing.
|
||||
Language = namedtuple('Language', 'code name')
|
||||
|
||||
|
||||
def released_languages():
|
||||
"""Retrieve the list of released languages.
|
||||
|
||||
Constructs a list of Language tuples by intersecting the
|
||||
list of valid language tuples with the list of released
|
||||
language codes.
|
||||
|
||||
Returns:
|
||||
list of Language: Languages in which full translations are available.
|
||||
|
||||
Example:
|
||||
|
||||
>>> print released_languages()
|
||||
[Language(code='en', name=u'English'), Language(code='fr', name=u'Français')]
|
||||
|
||||
"""
|
||||
released_language_codes = DarkLangConfig.current().released_languages_list
|
||||
default_language_code = settings.LANGUAGE_CODE
|
||||
|
||||
if default_language_code not in released_language_codes:
|
||||
released_language_codes.append(default_language_code)
|
||||
released_language_codes.sort()
|
||||
|
||||
# Intersect the list of valid language tuples with the list
|
||||
# of release language codes
|
||||
released_languages = [
|
||||
Language(tuple[0], tuple[1])
|
||||
for tuple in settings.LANGUAGES
|
||||
if tuple[0] in released_language_codes
|
||||
]
|
||||
|
||||
return released_languages
|
||||
|
||||
|
||||
def preferred_language(preferred_language_code):
|
||||
"""Retrieve the name of the user's preferred language.
|
||||
|
||||
Note:
|
||||
The preferred_language_code may be None. If this is the case,
|
||||
the if/else block will handle it by returning either the active
|
||||
language or the default language.
|
||||
|
||||
Args:
|
||||
preferred_language_code (str): The ISO 639 code corresponding
|
||||
to the user's preferred language.
|
||||
|
||||
Returns:
|
||||
unicode: The name of the user's preferred language.
|
||||
|
||||
"""
|
||||
active_language_code = get_language()
|
||||
|
||||
if preferred_language_code in settings.LANGUAGE_DICT:
|
||||
# If the user has indicated a preference for a valid
|
||||
# language, record their preferred language
|
||||
preferred_language = settings.LANGUAGE_DICT[preferred_language_code]
|
||||
elif active_language_code in settings.LANGUAGE_DICT:
|
||||
# Otherwise, set the language used in the current thread
|
||||
# as the preferred language
|
||||
preferred_language = settings.LANGUAGE_DICT[active_language_code]
|
||||
else:
|
||||
# Otherwise, use the default language
|
||||
preferred_language = settings.LANGUAGE_DICT[settings.LANGUAGE_CODE]
|
||||
|
||||
return preferred_language
|
||||
30
common/djangoapps/lang_pref/tests/test_api.py
Normal file
30
common/djangoapps/lang_pref/tests/test_api.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Tests for the language API. """
|
||||
|
||||
from django.test import TestCase
|
||||
import ddt
|
||||
|
||||
from lang_pref import api as language_api
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class LanguageApiTest(TestCase):
|
||||
|
||||
INVALID_LANGUAGE_CODES = ['', 'foo']
|
||||
|
||||
def test_released_languages(self):
|
||||
released_languages = language_api.released_languages()
|
||||
self.assertGreaterEqual(len(released_languages), 1)
|
||||
|
||||
def test_preferred_language(self):
|
||||
preferred_language = language_api.preferred_language('fr')
|
||||
self.assertEqual(preferred_language, u'Français')
|
||||
|
||||
@ddt.data(*INVALID_LANGUAGE_CODES)
|
||||
def test_invalid_preferred_language(self, language_code):
|
||||
preferred_language = language_api.preferred_language(language_code)
|
||||
self.assertEqual(preferred_language, u'English')
|
||||
|
||||
def test_no_preferred_language(self):
|
||||
preferred_language = language_api.preferred_language(None)
|
||||
self.assertEqual(preferred_language, u'English')
|
||||
@@ -414,4 +414,3 @@ def _validate_email(email):
|
||||
raise AccountEmailInvalid(
|
||||
u"Email '{email}' format is not valid".format(email=email)
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ but does NOT include basic account information such as username, password, and
|
||||
email address.
|
||||
|
||||
"""
|
||||
from user_api.models import UserProfile
|
||||
|
||||
from user_api.models import User, UserProfile, UserPreference
|
||||
from user_api.helpers import intercept_errors
|
||||
|
||||
|
||||
@@ -43,13 +44,13 @@ FULL_NAME_MAX_LENGTH = 255
|
||||
|
||||
@intercept_errors(ProfileInternalError, ignore_errors=[ProfileRequestError])
|
||||
def profile_info(username):
|
||||
"""Retrieve a user's profile information
|
||||
"""Retrieve a user's profile information.
|
||||
|
||||
Searches either by username or email.
|
||||
|
||||
At least one of the keyword args must be provided.
|
||||
|
||||
Arguments:
|
||||
Args:
|
||||
username (unicode): The username of the account to retrieve.
|
||||
|
||||
Returns:
|
||||
@@ -78,7 +79,7 @@ def update_profile(username, full_name=None):
|
||||
Args:
|
||||
username (unicode): The username associated with the account.
|
||||
|
||||
Keyword Arguments:
|
||||
Keyword Args:
|
||||
full_name (unicode): If provided, set the user's full name to this value.
|
||||
|
||||
Returns:
|
||||
@@ -102,31 +103,48 @@ def update_profile(username, full_name=None):
|
||||
|
||||
|
||||
@intercept_errors(ProfileInternalError, ignore_errors=[ProfileRequestError])
|
||||
def preference_info(username, preference_name):
|
||||
def preference_info(username):
|
||||
"""Retrieve information about a user's preferences.
|
||||
|
||||
Arguments:
|
||||
Args:
|
||||
username (unicode): The username of the account to retrieve.
|
||||
preference_name (unicode): The name of the preference to retrieve.
|
||||
|
||||
Returns:
|
||||
The JSON-deserialized value.
|
||||
dict: Empty if there is no user
|
||||
|
||||
"""
|
||||
pass
|
||||
preferences = UserPreference.objects.filter(user__username=username)
|
||||
|
||||
preferences_dict = {}
|
||||
for preference in preferences:
|
||||
preferences_dict[preference.key] = preference.value
|
||||
|
||||
return preferences_dict
|
||||
|
||||
|
||||
@intercept_errors(ProfileInternalError, ignore_errors=[ProfileRequestError])
|
||||
def update_preference(username, preference_name, preference_value):
|
||||
"""Update a user's preference.
|
||||
def update_preferences(username, **kwargs):
|
||||
"""Update a user's preferences.
|
||||
|
||||
Arguments:
|
||||
Sets the provided preferences for the given user.
|
||||
|
||||
Args:
|
||||
username (unicode): The username of the account to retrieve.
|
||||
preference_name (unicode): The name of the preference to set.
|
||||
preference_value (JSON-serializable): The new value for the preference.
|
||||
|
||||
Keyword Args:
|
||||
**kwargs (unicode): Arbitrary key-value preference pairs
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ProfileUserNotFound
|
||||
|
||||
"""
|
||||
pass
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise ProfileUserNotFound
|
||||
else:
|
||||
for key, value in kwargs.iteritems():
|
||||
UserPreference.set_preference(user, key, value)
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.test import TestCase
|
||||
import ddt
|
||||
from nose.tools import raises
|
||||
from dateutil.parser import parse as parse_datetime
|
||||
|
||||
from user_api.api import account as account_api
|
||||
from user_api.api import profile as profile_api
|
||||
from user_api.models import UserProfile
|
||||
@@ -13,9 +14,9 @@ from user_api.models import UserProfile
|
||||
@ddt.ddt
|
||||
class ProfileApiTest(TestCase):
|
||||
|
||||
USERNAME = u"frank-underwood"
|
||||
PASSWORD = u"ṕáśśẃőŕd"
|
||||
EMAIL = u"frank+underwood@example.com"
|
||||
USERNAME = u'frank-underwood'
|
||||
PASSWORD = u'ṕáśśẃőŕd'
|
||||
EMAIL = u'frank+underwood@example.com'
|
||||
|
||||
def test_create_profile(self):
|
||||
# Create a new account, which should have an empty profile by default.
|
||||
@@ -31,9 +32,9 @@ class ProfileApiTest(TestCase):
|
||||
|
||||
def test_update_full_name(self):
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
profile_api.update_profile(self.USERNAME, full_name=u"ȻħȺɍłɇs")
|
||||
profile = profile_api.profile_info(username=self.USERNAME)
|
||||
self.assertEqual(profile['full_name'], u"ȻħȺɍłɇs")
|
||||
profile_api.update_profile(self.USERNAME, full_name=u'ȻħȺɍłɇs')
|
||||
profile = profile_api.profile_info(self.USERNAME)
|
||||
self.assertEqual(profile['full_name'], u'ȻħȺɍłɇs')
|
||||
|
||||
@raises(profile_api.ProfileInvalidField)
|
||||
@ddt.data('', 'a' * profile_api.FULL_NAME_MAX_LENGTH + 'a')
|
||||
@@ -43,10 +44,10 @@ class ProfileApiTest(TestCase):
|
||||
|
||||
@raises(profile_api.ProfileUserNotFound)
|
||||
def test_update_profile_no_user(self):
|
||||
profile_api.update_profile(self.USERNAME, full_name="test")
|
||||
profile_api.update_profile(self.USERNAME, full_name='test')
|
||||
|
||||
def test_retrieve_profile_no_user(self):
|
||||
profile = profile_api.profile_info("does not exist")
|
||||
profile = profile_api.profile_info('does not exist')
|
||||
self.assertIs(profile, None)
|
||||
|
||||
def test_record_name_change_history(self):
|
||||
@@ -55,30 +56,53 @@ class ProfileApiTest(TestCase):
|
||||
# Change the name once
|
||||
# Since the original name was an empty string, expect that the list
|
||||
# of old names is empty
|
||||
profile_api.update_profile(self.USERNAME, full_name="new name")
|
||||
profile_api.update_profile(self.USERNAME, full_name='new name')
|
||||
meta = UserProfile.objects.get(user__username=self.USERNAME).get_meta()
|
||||
self.assertEqual(meta, {})
|
||||
|
||||
# Change the name again and expect the new name is stored in the history
|
||||
profile_api.update_profile(self.USERNAME, full_name="another new name")
|
||||
profile_api.update_profile(self.USERNAME, full_name='another new name')
|
||||
meta = UserProfile.objects.get(user__username=self.USERNAME).get_meta()
|
||||
|
||||
self.assertEqual(len(meta['old_names']), 1)
|
||||
name, rationale, timestamp = meta['old_names'][0]
|
||||
self.assertEqual(name, "new name")
|
||||
self.assertEqual(rationale, u"")
|
||||
self.assertEqual(name, 'new name')
|
||||
self.assertEqual(rationale, u'')
|
||||
self._assert_is_datetime(timestamp)
|
||||
|
||||
# Change the name a third time and expect both names are stored in the history
|
||||
profile_api.update_profile(self.USERNAME, full_name="yet another new name")
|
||||
profile_api.update_profile(self.USERNAME, full_name='yet another new name')
|
||||
meta = UserProfile.objects.get(user__username=self.USERNAME).get_meta()
|
||||
|
||||
self.assertEqual(len(meta['old_names']), 2)
|
||||
name, rationale, timestamp = meta['old_names'][1]
|
||||
self.assertEqual(name, "another new name")
|
||||
self.assertEqual(rationale, u"")
|
||||
self.assertEqual(name, 'another new name')
|
||||
self.assertEqual(rationale, u'')
|
||||
self._assert_is_datetime(timestamp)
|
||||
|
||||
def test_update_and_retrieve_preference_info(self):
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
|
||||
profile_api.update_preferences(self.USERNAME, preference_key='preference_value')
|
||||
|
||||
preferences = profile_api.preference_info(self.USERNAME)
|
||||
self.assertEqual(preferences['preference_key'], 'preference_value')
|
||||
|
||||
@raises(profile_api.ProfileUserNotFound)
|
||||
def test_retrieve_and_update_preference_info_no_user(self):
|
||||
preferences = profile_api.preference_info(self.USERNAME)
|
||||
self.assertEqual(preferences, {})
|
||||
|
||||
profile_api.update_preferences(self.USERNAME, preference_key='preference_value')
|
||||
|
||||
def test_update_and_retrieve_preference_info_unicode(self):
|
||||
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
|
||||
|
||||
profile_api.update_preferences(self.USERNAME, **{u'ⓟⓡⓔⓕⓔⓡⓔⓝⓒⓔ_ⓚⓔⓨ': u'ǝnןɐʌ_ǝɔuǝɹǝɟǝɹd'})
|
||||
|
||||
preferences = profile_api.preference_info(self.USERNAME)
|
||||
self.assertEqual(preferences[u'ⓟⓡⓔⓕⓔⓡⓔⓝⓒⓔ_ⓚⓔⓨ'], u'ǝnןɐʌ_ǝɔuǝɹǝɟǝɹd')
|
||||
|
||||
def _assert_is_datetime(self, timestamp):
|
||||
if not timestamp:
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user