Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
895bb5e
LMS: adding language selector to user dashboard (WIP)
talbs Feb 2, 2014
cb6b52f
wiring for language selector
Feb 3, 2014
a520770
Added dark lang database fixture to bok choy tests
Feb 6, 2014
d867e87
Acceptance test for language selector
Feb 6, 2014
c41d814
LMS: simplifying language settings modal controls UI
talbs Feb 10, 2014
7d81a51
Moved UserPreferences to common
Feb 10, 2014
5525726
Added middleware for handling language changes
Feb 11, 2014
77cce3a
Added acceptance test for language persistence
Feb 11, 2014
be189e6
Store user preferences for languages
dianakhuang Feb 11, 2014
a6f147a
LMS: revising modal UI to support translators
talbs Feb 13, 2014
e94b1a5
If we run into issues with languages, use default
dianakhuang Feb 13, 2014
59aa06f
Add back in the fake2 language
dianakhuang Feb 13, 2014
a07d243
Clean up the display and dialog to use user preferences
dianakhuang Feb 13, 2014
a51ab4f
LMS: adding iconography to language pref on dashboard UI
talbs Feb 13, 2014
d00a0f5
LMS: adding in supplemental 'volunteer to be a translator' action to …
talbs Feb 13, 2014
cb209fa
LMS: revising color of language icon
talbs Feb 13, 2014
4868679
Clean up tests.
dianakhuang Feb 14, 2014
7e38c3a
Use a given default for getting a preference
dianakhuang Feb 14, 2014
f6e14e6
Change setlang url
dianakhuang Feb 14, 2014
afdd8d6
Better dashboard display behavior
dianakhuang Feb 14, 2014
c235ec3
Open up translation docs in separate tab.
dianakhuang Feb 14, 2014
efe7bda
Fixed broken acceptance tests
Feb 14, 2014
b61649f
Refactor out new lang_pref djangoapp
dianakhuang Feb 14, 2014
0553754
Fix acceptance tests
Feb 14, 2014
ff0a6fb
Update cms urls for language preferences
dianakhuang Feb 14, 2014
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
5 changes: 5 additions & 0 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,13 @@

# Dark-launching languages
'dark_lang',

# Student identity reverification
'reverification',

# User preferences
'user_api',
'django_openid_auth',
)


Expand Down
3 changes: 3 additions & 0 deletions cms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@

url(r'^xmodule/', include('pipeline_js.urls')),
url(r'^heartbeat$', include('heartbeat.urls')),

url(r'^user_api/', include('user_api.urls')),
url(r'^lang_pref/', include('lang_pref.urls')),
)

# User creation and updating views
Expand Down
2 changes: 2 additions & 0 deletions common/djangoapps/dark_lang/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class DarkLangConfig(ConfigurationModel):
def released_languages_list(self):
"""
``released_languages`` as a list of language codes.

Example: ['it', 'de-at', 'es', 'pt-br']
"""
if not self.released_languages.strip(): # pylint: disable=no-member
return []
Expand Down
6 changes: 6 additions & 0 deletions common/djangoapps/lang_pref/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
Useful information for setting the language preference
"""

# this is the UserPreference key for the user's preferred language
LANGUAGE_KEY = 'pref-lang'
25 changes: 25 additions & 0 deletions common/djangoapps/lang_pref/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Middleware for Language Preferences
"""

from user_api.models import UserPreference
from lang_pref import LANGUAGE_KEY


class LanguagePreferenceMiddleware(object):
"""
Middleware for user preferences.

Ensures that, once set, a user's preferences are reflected in the page
whenever they are logged in.
"""

def process_request(self, request):
"""
If a user's UserPreference contains a language preference and there is
no language set on the session (i.e. from dark language overrides), use the user's preference.
"""
if request.user.is_authenticated() and 'django_language' not in request.session:
user_pref = UserPreference.get_preference(request.user, LANGUAGE_KEY)
if user_pref:
request.session['django_language'] = user_pref
42 changes: 42 additions & 0 deletions common/djangoapps/lang_pref/tests/test_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.test import TestCase
from django.test.client import RequestFactory
from django.contrib.sessions.middleware import SessionMiddleware

from lang_pref.middleware import LanguagePreferenceMiddleware
from user_api.models import UserPreference
from lang_pref import LANGUAGE_KEY
from student.tests.factories import UserFactory


class TestUserPreferenceMiddleware(TestCase):
"""
Tests to make sure user preferences are getting properly set in the middleware
"""

def setUp(self):
self.middleware = LanguagePreferenceMiddleware()
self.session_middleware = SessionMiddleware()
self.user = UserFactory.create()
self.request = RequestFactory().get('/somewhere')
self.request.user = self.user
self.session_middleware.process_request(self.request)

def test_no_language_set_in_session_or_prefs(self):
# nothing set in the session or the prefs
self.middleware.process_request(self.request)
self.assertNotIn('django_language', self.request.session)

def test_language_in_user_prefs(self):
# language set in the user preferences and not the session
UserPreference.set_preference(self.user, LANGUAGE_KEY, 'eo')
self.middleware.process_request(self.request)
self.assertEquals(self.request.session['django_language'], 'eo')

def test_language_in_session(self):
# language set in both the user preferences and session,
# session should get precedence
self.request.session['django_language'] = 'en'
UserPreference.set_preference(self.user, LANGUAGE_KEY, 'eo')
self.middleware.process_request(self.request)

self.assertEquals(self.request.session['django_language'], 'en')
34 changes: 34 additions & 0 deletions common/djangoapps/lang_pref/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
Tests for the language setting view
"""
from django.core.urlresolvers import reverse
from django.test import TestCase
from student.tests.factories import UserFactory
from user_api.models import UserPreference
from lang_pref import LANGUAGE_KEY


class TestLanguageSetting(TestCase):
"""
Test setting languages
"""
def test_set_preference_happy(self):
user = UserFactory.create()
self.client.login(username=user.username, password='test')

lang = 'en'
response = self.client.post(reverse('lang_pref_set_language'), {'language': lang})

self.assertEquals(response.status_code, 200)
user_pref = UserPreference.get_preference(user, LANGUAGE_KEY)
self.assertEqual(user_pref, lang)

def test_set_preference_missing_lang(self):
user = UserFactory.create()
self.client.login(username=user.username, password='test')

response = self.client.post(reverse('lang_pref_set_language'))

self.assertEquals(response.status_code, 400)

self.assertIsNone(UserPreference.get_preference(user, LANGUAGE_KEY))
10 changes: 10 additions & 0 deletions common/djangoapps/lang_pref/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Urls for managing language preferences
"""

from django.conf.urls import patterns, url

urlpatterns = patterns(
'',
url(r'^setlang/', 'lang_pref.views.set_language', name='lang_pref_set_language')
)
23 changes: 23 additions & 0 deletions common/djangoapps/lang_pref/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
Views for accessing language preferences
"""
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest

from user_api.models import UserPreference
from lang_pref import LANGUAGE_KEY


@login_required
def set_language(request):
"""
This view is called when the user would like to set a language preference
"""
user = request.user
lang_pref = request.POST.get('language', None)

if lang_pref:
UserPreference.set_preference(user, LANGUAGE_KEY, lang_pref)
return HttpResponse('{"success": true}')

return HttpResponseBadRequest('no language provided')
56 changes: 39 additions & 17 deletions common/djangoapps/student/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

from verify_student.models import SoftwareSecurePhotoVerification, MidcourseReverificationWindow
from certificates.models import CertificateStatuses, certificate_status_for_student
from dark_lang.models import DarkLangConfig

from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.exceptions import ItemNotFoundError
Expand All @@ -61,6 +62,8 @@

from bulk_email.models import Optout, CourseAuthorization
import shoppingcart
from user_api.models import UserPreference
from lang_pref import LANGUAGE_KEY

import track.views

Expand Down Expand Up @@ -468,23 +471,42 @@ def dashboard(request):
# we'll display the banner
denied_banner = any(item.display for item in reverifications["denied"])

context = {'course_enrollment_pairs': course_enrollment_pairs,
'course_optouts': course_optouts,
'message': message,
'external_auth_map': external_auth_map,
'staff_access': staff_access,
'errored_courses': errored_courses,
'show_courseware_links_for': show_courseware_links_for,
'all_course_modes': course_modes,
'cert_statuses': cert_statuses,
'show_email_settings_for': show_email_settings_for,
'reverifications': reverifications,
'verification_status': verification_status,
'verification_msg': verification_msg,
'show_refund_option_for': show_refund_option_for,
'denied_banner': denied_banner,
'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
}
language_options = DarkLangConfig.current().released_languages_list

# add in the default language if it's not in the list of released languages
if settings.LANGUAGE_CODE not in language_options:
language_options.append(settings.LANGUAGE_CODE)

# try to get the prefered language for the user
cur_lang_code = UserPreference.get_preference(request.user, LANGUAGE_KEY)
if cur_lang_code:
# if the user has a preference, get the name from the code
current_language = settings.LANGUAGE_DICT[cur_lang_code]
else:
# if the user doesn't have a preference, use the default language
current_language = settings.LANGUAGE_DICT[settings.LANGUAGE_CODE]

context = {
'course_enrollment_pairs': course_enrollment_pairs,
'course_optouts': course_optouts,
'message': message,
'external_auth_map': external_auth_map,
'staff_access': staff_access,
'errored_courses': errored_courses,
'show_courseware_links_for': show_courseware_links_for,
'all_course_modes': course_modes,
'cert_statuses': cert_statuses,
'show_email_settings_for': show_email_settings_for,
'reverifications': reverifications,
'verification_status': verification_status,
'verification_msg': verification_msg,
'show_refund_option_for': show_refund_option_for,
'denied_banner': denied_banner,
'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
'language_options': language_options,
'current_language': current_language,
'current_language_code': cur_lang_code,
}

return render_to_response('dashboard.html', context)

Expand Down
35 changes: 35 additions & 0 deletions common/djangoapps/user_api/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.contrib.auth.models import User
from django.db import models


class UserPreference(models.Model):
"""A user's preference, stored as generic text to be processed by client"""
user = models.ForeignKey(User, db_index=True, related_name="+")
key = models.CharField(max_length=255, db_index=True)
value = models.TextField()

class Meta:
unique_together = ("user", "key")

@classmethod
def set_preference(cls, user, preference_key, preference_value):
"""
Sets the user preference for a given key
"""
user_pref, _ = cls.objects.get_or_create(user=user, key=preference_key)
user_pref.value = preference_value
user_pref.save()

@classmethod
def get_preference(cls, user, preference_key, default=None):
"""
Gets the user preference value for a given key

Returns the given default if there isn't a preference for the given key
"""

try:
user_pref = cls.objects.get(user=user, key=preference_key)
return user_pref.value
except cls.DoesNotExist:
return default
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.test import TestCase
from student.tests.factories import UserFactory
from user_api.tests.factories import UserPreferenceFactory
from user_api.models import UserPreference


class UserPreferenceModelTest(TestCase):
Expand All @@ -26,3 +27,21 @@ def test_arbitrary_values(self):
key="testkey3",
value="\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\xad\xe5\x9b\xbd\xe6\x96\x87\xe5\xad\x97'"
)

def test_get_set_preference(self):

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.

there's not a whole lot of English here to explain what you're testing and why

# Checks that you can set a preference and get that preference later
# Also, tests that no preference is returned for keys that are not set

user = UserFactory.create()
key = 'testkey'
value = 'testvalue'

# does a round trip
UserPreference.set_preference(user, key, value)
pref = UserPreference.get_preference(user, key)

self.assertEqual(pref, value)

# get preference for key that doesn't exist for user
pref = UserPreference.get_preference(user, 'testkey_none')
self.assertIsNone(pref)
Loading