Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
3deb3a3c
Commit
3deb3a3c
authored
May 01, 2017
by
Calen Pennington
Committed by
GitHub
May 01, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14977 from cpennington/cale/fix-learner-542
Cale/fix learner 542
parents
09593998
2ca367a1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
191 additions
and
100 deletions
+191
-100
cms/envs/aws.py
+2
-0
cms/envs/common.py
+2
-0
common/djangoapps/student/cookies.py
+3
-3
lms/djangoapps/ccx/tests/test_field_override_performance.py
+27
-27
lms/djangoapps/courseware/tests/test_course_info.py
+2
-2
lms/djangoapps/courseware/tests/test_i18n.py
+14
-10
lms/djangoapps/courseware/tests/test_views.py
+5
-5
lms/djangoapps/django_comment_client/base/tests.py
+4
-4
lms/envs/aws.py
+2
-0
lms/envs/common.py
+2
-0
lms/envs/devstack_docker.py
+1
-0
openedx/core/djangoapps/bookmarks/tests/test_views.py
+1
-1
openedx/core/djangoapps/lang_pref/__init__.py
+4
-0
openedx/core/djangoapps/lang_pref/middleware.py
+46
-12
openedx/core/djangoapps/lang_pref/tests/test_middleware.py
+0
-0
openedx/core/djangoapps/lang_pref/views.py
+9
-2
openedx/core/djangoapps/user_api/accounts/tests/test_views.py
+7
-7
openedx/core/djangoapps/user_api/errors.py
+2
-0
openedx/core/djangoapps/user_api/helpers.py
+16
-2
openedx/core/djangoapps/user_api/preferences/api.py
+19
-9
openedx/core/djangoapps/user_api/preferences/tests/test_api.py
+2
-3
openedx/core/djangoapps/user_api/serializers.py
+1
-6
openedx/core/djangoapps/user_api/tests/test_helpers.py
+17
-4
openedx/core/djangoapps/user_api/views.py
+3
-3
No files found.
cms/envs/aws.py
View file @
3deb3a3c
...
...
@@ -221,6 +221,8 @@ GIT_REPO_EXPORT_DIR = ENV_TOKENS.get('GIT_REPO_EXPORT_DIR', '/edx/var/edxapp/exp
# Translation overrides
LANGUAGES
=
ENV_TOKENS
.
get
(
'LANGUAGES'
,
LANGUAGES
)
LANGUAGE_CODE
=
ENV_TOKENS
.
get
(
'LANGUAGE_CODE'
,
LANGUAGE_CODE
)
LANGUAGE_COOKIE
=
ENV_TOKENS
.
get
(
'LANGUAGE_COOKIE'
,
LANGUAGE_COOKIE
)
USE_I18N
=
ENV_TOKENS
.
get
(
'USE_I18N'
,
USE_I18N
)
ENV_FEATURES
=
ENV_TOKENS
.
get
(
'FEATURES'
,
{})
...
...
cms/envs/common.py
View file @
3deb3a3c
...
...
@@ -547,6 +547,8 @@ TIME_ZONE = 'America/New_York' # http://en.wikipedia.org/wiki/List_of_tz_zones_
LANGUAGE_CODE
=
'en'
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGES_BIDI
=
lms
.
envs
.
common
.
LANGUAGES_BIDI
LANGUAGE_COOKIE
=
lms
.
envs
.
common
.
LANGUAGE_COOKIE
LANGUAGES
=
lms
.
envs
.
common
.
LANGUAGES
LANGUAGE_DICT
=
dict
(
LANGUAGES
)
...
...
common/djangoapps/student/cookies.py
View file @
3deb3a3c
...
...
@@ -17,7 +17,7 @@ from student.models import CourseEnrollment
CREATE_LOGON_COOKIE
=
Signal
(
providing_args
=
[
'user'
,
'response'
])
def
_get
_cookie_settings
(
request
):
def
standard
_cookie_settings
(
request
):
""" Returns the common cookie settings (e.g. expiration time). """
if
request
.
session
.
get_expire_at_browser_close
():
...
...
@@ -73,7 +73,7 @@ def set_logged_in_cookies(request, response, user):
HttpResponse
"""
cookie_settings
=
_get
_cookie_settings
(
request
)
cookie_settings
=
standard
_cookie_settings
(
request
)
# Backwards compatibility: set the cookie indicating that the user
# is logged in. This is just a boolean value, so it's not very useful.
...
...
@@ -96,7 +96,7 @@ def set_logged_in_cookies(request, response, user):
def
set_user_info_cookie
(
response
,
request
):
""" Sets the user info cookie on the response. """
cookie_settings
=
_get
_cookie_settings
(
request
)
cookie_settings
=
standard
_cookie_settings
(
request
)
# In production, TLS should be enabled so that this cookie is encrypted
# when we send it. We also need to set "secure" to True so that the browser
...
...
lms/djangoapps/ccx/tests/test_field_override_performance.py
View file @
3deb3a3c
...
...
@@ -231,18 +231,18 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase):
# # of sql queries to default,
# # of mongo queries,
# )
(
'no_overrides'
,
1
,
True
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
2
,
True
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
3
,
True
,
False
):
(
2
5
,
1
),
(
'ccx'
,
1
,
True
,
False
):
(
2
5
,
1
),
(
'ccx'
,
2
,
True
,
False
):
(
2
5
,
1
),
(
'ccx'
,
3
,
True
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
1
,
False
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
2
,
False
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
3
,
False
,
False
):
(
2
5
,
1
),
(
'ccx'
,
1
,
False
,
False
):
(
2
5
,
1
),
(
'ccx'
,
2
,
False
,
False
):
(
2
5
,
1
),
(
'ccx'
,
3
,
False
,
False
):
(
2
5
,
1
),
(
'no_overrides'
,
1
,
True
,
False
):
(
2
3
,
1
),
(
'no_overrides'
,
2
,
True
,
False
):
(
2
3
,
1
),
(
'no_overrides'
,
3
,
True
,
False
):
(
2
3
,
1
),
(
'ccx'
,
1
,
True
,
False
):
(
2
3
,
1
),
(
'ccx'
,
2
,
True
,
False
):
(
2
3
,
1
),
(
'ccx'
,
3
,
True
,
False
):
(
2
3
,
1
),
(
'no_overrides'
,
1
,
False
,
False
):
(
2
3
,
1
),
(
'no_overrides'
,
2
,
False
,
False
):
(
2
3
,
1
),
(
'no_overrides'
,
3
,
False
,
False
):
(
2
3
,
1
),
(
'ccx'
,
1
,
False
,
False
):
(
2
3
,
1
),
(
'ccx'
,
2
,
False
,
False
):
(
2
3
,
1
),
(
'ccx'
,
3
,
False
,
False
):
(
2
3
,
1
),
}
...
...
@@ -254,19 +254,19 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase):
__test__
=
True
TEST_DATA
=
{
(
'no_overrides'
,
1
,
True
,
False
):
(
2
5
,
3
),
(
'no_overrides'
,
2
,
True
,
False
):
(
2
5
,
3
),
(
'no_overrides'
,
3
,
True
,
False
):
(
2
5
,
3
),
(
'ccx'
,
1
,
True
,
False
):
(
2
5
,
3
),
(
'ccx'
,
2
,
True
,
False
):
(
2
5
,
3
),
(
'ccx'
,
3
,
True
,
False
):
(
2
5
,
3
),
(
'ccx'
,
1
,
True
,
True
):
(
2
6
,
3
),
(
'ccx'
,
2
,
True
,
True
):
(
2
6
,
3
),
(
'ccx'
,
3
,
True
,
True
):
(
2
6
,
3
),
(
'no_overrides'
,
1
,
False
,
False
):
(
2
5
,
3
),
(
'no_overrides'
,
2
,
False
,
False
):
(
2
5
,
3
),
(
'no_overrides'
,
3
,
False
,
False
):
(
2
5
,
3
),
(
'ccx'
,
1
,
False
,
False
):
(
2
5
,
3
),
(
'ccx'
,
2
,
False
,
False
):
(
2
5
,
3
),
(
'ccx'
,
3
,
False
,
False
):
(
2
5
,
3
),
(
'no_overrides'
,
1
,
True
,
False
):
(
2
3
,
3
),
(
'no_overrides'
,
2
,
True
,
False
):
(
2
3
,
3
),
(
'no_overrides'
,
3
,
True
,
False
):
(
2
3
,
3
),
(
'ccx'
,
1
,
True
,
False
):
(
2
3
,
3
),
(
'ccx'
,
2
,
True
,
False
):
(
2
3
,
3
),
(
'ccx'
,
3
,
True
,
False
):
(
2
3
,
3
),
(
'ccx'
,
1
,
True
,
True
):
(
2
4
,
3
),
(
'ccx'
,
2
,
True
,
True
):
(
2
4
,
3
),
(
'ccx'
,
3
,
True
,
True
):
(
2
4
,
3
),
(
'no_overrides'
,
1
,
False
,
False
):
(
2
3
,
3
),
(
'no_overrides'
,
2
,
False
,
False
):
(
2
3
,
3
),
(
'no_overrides'
,
3
,
False
,
False
):
(
2
3
,
3
),
(
'ccx'
,
1
,
False
,
False
):
(
2
3
,
3
),
(
'ccx'
,
2
,
False
,
False
):
(
2
3
,
3
),
(
'ccx'
,
3
,
False
,
False
):
(
2
3
,
3
),
}
lms/djangoapps/courseware/tests/test_course_info.py
View file @
3deb3a3c
...
...
@@ -367,7 +367,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
self
.
assertEqual
(
resp
.
status_code
,
200
)
def
test_num_queries_instructor_paced
(
self
):
self
.
fetch_course_info_with_queries
(
self
.
instructor_paced_course
,
21
,
4
)
self
.
fetch_course_info_with_queries
(
self
.
instructor_paced_course
,
18
,
4
)
def
test_num_queries_self_paced
(
self
):
self
.
fetch_course_info_with_queries
(
self
.
self_paced_course
,
21
,
4
)
self
.
fetch_course_info_with_queries
(
self
.
self_paced_course
,
18
,
4
)
lms/djangoapps/courseware/tests/test_i18n.py
View file @
3deb3a3c
...
...
@@ -2,6 +2,7 @@
Tests i18n in courseware
"""
import
json
import
re
from
django.conf
import
settings
...
...
@@ -14,8 +15,6 @@ from nose.plugins.attrib import attr
from
openedx.core.djangoapps.dark_lang.models
import
DarkLangConfig
from
openedx.core.djangoapps.lang_pref
import
LANGUAGE_KEY
from
openedx.core.djangoapps.user_api.preferences.api
import
set_user_preference
from
student.models
import
UserProfile
from
student.tests.factories
import
UserFactory
...
...
@@ -61,8 +60,7 @@ class BaseI18nTestCase(TestCase):
"""
# Create one user and save it to the database
email
=
'test@edx.org'
self
.
user
=
UserFactory
.
build
(
username
=
'test'
,
email
=
email
,
password
=
self
.
pwd
)
self
.
user
.
save
()
self
.
user
=
UserFactory
.
create
(
username
=
'test'
,
email
=
email
,
password
=
self
.
pwd
)
def
user_login
(
self
):
"""
...
...
@@ -119,7 +117,6 @@ class I18nRegressionTests(BaseI18nTestCase):
def
test_unreleased_lang_resolution
(
self
):
# Regression test; LOC-85
UserProfile
.
objects
.
create
(
user
=
self
.
user
)
self
.
release_languages
(
'fa'
)
self
.
user_login
()
...
...
@@ -136,7 +133,6 @@ class I18nRegressionTests(BaseI18nTestCase):
self
.
assert_tag_has_attr
(
response
.
content
,
"html"
,
"lang"
,
"fa-ir"
)
def
test_preview_lang
(
self
):
UserProfile
.
objects
.
create
(
user
=
self
.
user
)
self
.
user_login
()
# Regression test; LOC-87
...
...
@@ -172,9 +168,17 @@ class I18nLangPrefTests(BaseI18nTestCase):
"""
def
setUp
(
self
):
super
(
I18nLangPrefTests
,
self
)
.
setUp
()
UserProfile
.
objects
.
create
(
user
=
self
.
user
)
self
.
user_login
()
def
set_lang_preference
(
self
,
language
):
"""Sets the user's language preference, allowing the LangPref middleware to operate to set the preference cookie."""
response
=
self
.
client
.
patch
(
reverse
(
'preferences_api'
,
args
=
[
self
.
user
.
username
]),
json
.
dumps
({
LANGUAGE_KEY
:
language
}),
content_type
=
"application/merge-patch+json"
)
self
.
assertEqual
(
response
.
status_code
,
204
)
def
test_lang_preference
(
self
):
# Regression test; LOC-87
self
.
release_languages
(
'ar, es-419'
)
...
...
@@ -184,13 +188,13 @@ class I18nLangPrefTests(BaseI18nTestCase):
self
.
assert_tag_has_attr
(
response
.
content
,
"html"
,
"lang"
,
self
.
site_lang
)
# Set user language preference
se
t_user_preference
(
self
.
user
,
LANGUAGE_KEY
,
'ar'
)
se
lf
.
set_lang_preference
(
'ar'
)
# and verify we now get an ar response
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assert_tag_has_attr
(
response
.
content
,
"html"
,
"lang"
,
'ar'
)
# Verify that switching language preference gives the right language
se
t_user_preference
(
self
.
user
,
LANGUAGE_KEY
,
'es-419'
)
se
lf
.
set_lang_preference
(
'es-419'
)
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assert_tag_has_attr
(
response
.
content
,
"html"
,
"lang"
,
'es-419'
)
...
...
@@ -199,7 +203,7 @@ class I18nLangPrefTests(BaseI18nTestCase):
self
.
release_languages
(
'ar, es-419'
)
# Set user language preference
se
t_user_preference
(
self
.
user
,
LANGUAGE_KEY
,
'ar'
)
se
lf
.
set_lang_preference
(
'ar'
)
# Verify preview-lang takes precedence
self
.
client
.
post
(
self
.
preview_language_url
,
{
'preview_lang'
:
'eo'
,
'set_language'
:
'set_language'
})
response
=
self
.
client
.
get
(
self
.
url
)
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
3deb3a3c
...
...
@@ -206,8 +206,8 @@ class IndexQueryTestCase(ModuleStoreTestCase):
NUM_PROBLEMS
=
20
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
10
,
14
7
),
(
ModuleStoreEnum
.
Type
.
split
,
4
,
14
7
),
(
ModuleStoreEnum
.
Type
.
mongo
,
10
,
14
1
),
(
ModuleStoreEnum
.
Type
.
split
,
4
,
14
1
),
)
@ddt.unpack
def
test_index_query_counts
(
self
,
store_type
,
expected_mongo_query_count
,
expected_mysql_query_count
):
...
...
@@ -1408,12 +1408,12 @@ class ProgressPageTests(ModuleStoreTestCase):
"""Test that query counts remain the same for self-paced and instructor-paced courses."""
SelfPacedConfiguration
(
enabled
=
self_paced_enabled
)
.
save
()
self
.
setup_course
(
self_paced
=
self_paced
)
with
self
.
assertNumQueries
(
42
),
check_mongo_calls
(
1
):
with
self
.
assertNumQueries
(
39
),
check_mongo_calls
(
1
):
self
.
_get_progress_page
()
@ddt.data
(
(
False
,
42
,
28
),
(
True
,
3
5
,
24
)
(
False
,
39
,
25
),
(
True
,
3
2
,
21
)
)
@ddt.unpack
def
test_progress_queries
(
self
,
enable_waffle
,
initial
,
subsequent
):
...
...
lms/djangoapps/django_comment_client/base/tests.py
View file @
3deb3a3c
...
...
@@ -377,8 +377,8 @@ class ViewsQueryCountTestCase(
return
inner
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
3
,
4
,
3
1
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
13
,
3
1
),
(
ModuleStoreEnum
.
Type
.
mongo
,
3
,
4
,
3
0
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
13
,
3
0
),
)
@ddt.unpack
@count_queries
...
...
@@ -386,8 +386,8 @@ class ViewsQueryCountTestCase(
self
.
create_thread_helper
(
mock_request
)
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
3
,
3
,
2
7
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
10
,
2
7
),
(
ModuleStoreEnum
.
Type
.
mongo
,
3
,
3
,
2
6
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
10
,
2
6
),
)
@ddt.unpack
@count_queries
...
...
lms/envs/aws.py
View file @
3deb3a3c
...
...
@@ -315,6 +315,8 @@ TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE)
LANGUAGES
=
ENV_TOKENS
.
get
(
'LANGUAGES'
,
LANGUAGES
)
LANGUAGE_DICT
=
dict
(
LANGUAGES
)
LANGUAGE_CODE
=
ENV_TOKENS
.
get
(
'LANGUAGE_CODE'
,
LANGUAGE_CODE
)
LANGUAGE_COOKIE
=
ENV_TOKENS
.
get
(
'LANGUAGE_COOKIE'
,
LANGUAGE_COOKIE
)
USE_I18N
=
ENV_TOKENS
.
get
(
'USE_I18N'
,
USE_I18N
)
# Additional installed apps
...
...
lms/envs/common.py
View file @
3deb3a3c
...
...
@@ -863,6 +863,8 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
# these languages display right to left
LANGUAGES_BIDI
=
(
"he"
,
"ar"
,
"fa"
,
"ur"
,
"fa-ir"
,
"rtl"
)
LANGUAGE_COOKIE
=
"openedx-language-preference"
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
LANGUAGES
=
(
(
'en'
,
u'English'
),
...
...
lms/envs/devstack_docker.py
View file @
3deb3a3c
...
...
@@ -30,6 +30,7 @@ FEATURES.update({
'ENABLE_COURSEWARE_SEARCH'
:
False
,
'ENABLE_COURSE_DISCOVERY'
:
False
,
'ENABLE_DASHBOARD_SEARCH'
:
False
,
'SHOW_LANGUAGE_SELECTOR'
:
True
})
ENABLE_MKTG_SITE
=
os
.
environ
.
get
(
'ENABLE_MARKETING_SITE'
,
False
)
...
...
openedx/core/djangoapps/bookmarks/tests/test_views.py
View file @
3deb3a3c
...
...
@@ -268,7 +268,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
self
.
assertEqual
(
response
.
data
[
'developer_message'
],
u'Parameter usage_id not provided.'
)
# Send empty data dictionary.
with
self
.
assertNumQueries
(
8
):
# No queries for bookmark table.
with
self
.
assertNumQueries
(
7
):
# No queries for bookmark table.
response
=
self
.
send_post
(
client
=
self
.
client
,
url
=
reverse
(
'bookmarks'
),
...
...
openedx/core/djangoapps/lang_pref/__init__.py
View file @
3deb3a3c
...
...
@@ -4,3 +4,7 @@ Useful information for setting the language preference
# this is the UserPreference key for the user's preferred language
LANGUAGE_KEY
=
'pref-lang'
LANGUAGE_HEADER
=
'HTTP_ACCEPT_LANGUAGE'
COOKIE_DURATION
=
14
*
24
*
60
*
60
# 14 days in seconds
openedx/core/djangoapps/lang_pref/middleware.py
View file @
3deb3a3c
...
...
@@ -2,12 +2,17 @@
Middleware for Language Preferences
"""
from
django.conf
import
settings
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
LANGUAGE_KEY
from
openedx.core.djangoapps.lang_pref.api
import
released_languages
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preference
,
delete_user_preference
from
openedx.core.djangoapps.lang_pref
import
(
LANGUAGE_KEY
,
LANGUAGE_HEADER
,
COOKIE_DURATION
)
from
openedx.core.djangoapps.user_api.preferences.api
import
(
get_user_preference
,
delete_user_preference
,
set_user_preference
)
from
openedx.core.djangoapps.user_api.errors
import
UserAPIInternalError
,
UserAPIRequestError
class
LanguagePreferenceMiddleware
(
object
):
...
...
@@ -21,17 +26,46 @@ class LanguagePreferenceMiddleware(object):
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.
"""
languages
=
released_languages
()
system_released_languages
=
[
seq
[
0
]
for
seq
in
languages
]
cookie_lang
=
request
.
COOKIES
.
get
(
settings
.
LANGUAGE_COOKIE
,
None
)
if
cookie_lang
:
if
request
.
user
.
is_authenticated
():
set_user_preference
(
request
.
user
,
LANGUAGE_KEY
,
cookie_lang
)
accept_header
=
request
.
META
.
get
(
LANGUAGE_HEADER
,
None
)
if
accept_header
:
current_langs
=
parse_accept_lang_header
(
accept_header
)
# Promote the cookie_lang over any language currently in the accept header
current_langs
=
[(
lang
,
qvalue
)
for
(
lang
,
qvalue
)
in
current_langs
if
lang
!=
cookie_lang
]
current_langs
.
insert
(
0
,
(
cookie_lang
,
1
))
accept_header
=
","
.
join
(
"{};q={}"
.
format
(
lang
,
qvalue
)
for
(
lang
,
qvalue
)
in
current_langs
)
else
:
accept_header
=
cookie_lang
request
.
META
[
LANGUAGE_HEADER
]
=
accept_header
def
process_response
(
self
,
request
,
response
):
# If the user is logged in, check for their language preference
if
request
.
user
.
is_authenticated
():
if
getattr
(
request
,
'user'
,
None
)
and
request
.
user
.
is_authenticated
():
# Get the user's language preference
user_pref
=
get_user_preference
(
request
.
user
,
LANGUAGE_KEY
)
# Set it to the LANGUAGE_SESSION_KEY (Django-specific session setting governing language pref)
if
user_pref
:
if
user_pref
in
system_released_languages
:
request
.
session
[
LANGUAGE_SESSION_KEY
]
=
user_pref
try
:
user_pref
=
get_user_preference
(
request
.
user
,
LANGUAGE_KEY
)
except
(
UserAPIRequestError
,
UserAPIInternalError
):
# If we can't find the user preferences, then don't modify the cookie
pass
else
:
# Set it in the LANGUAGE_COOKIE
if
user_pref
:
response
.
set_cookie
(
settings
.
LANGUAGE_COOKIE
,
value
=
user_pref
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
max_age
=
COOKIE_DURATION
,
)
else
:
delete_user_preference
(
request
.
user
,
LANGUAGE_KEY
)
response
.
delete_cookie
(
settings
.
LANGUAGE_COOKIE
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
)
return
response
openedx/core/djangoapps/lang_pref/tests/test_middleware.py
View file @
3deb3a3c
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/lang_pref/views.py
View file @
3deb3a3c
...
...
@@ -9,7 +9,7 @@ from django.http import HttpResponse
from
django.views.decorators.csrf
import
ensure_csrf_cookie
from
django.utils.translation
import
LANGUAGE_SESSION_KEY
from
openedx.core.djangoapps.lang_pref
import
LANGUAGE_KEY
from
openedx.core.djangoapps.lang_pref
import
LANGUAGE_KEY
,
COOKIE_DURATION
@ensure_csrf_cookie
...
...
@@ -17,9 +17,16 @@ def update_session_language(request):
"""
Update the language session key.
"""
response
=
HttpResponse
(
200
)
if
request
.
method
==
'PATCH'
:
data
=
json
.
loads
(
request
.
body
)
language
=
data
.
get
(
LANGUAGE_KEY
,
settings
.
LANGUAGE_CODE
)
if
request
.
session
.
get
(
LANGUAGE_SESSION_KEY
,
None
)
!=
language
:
request
.
session
[
LANGUAGE_SESSION_KEY
]
=
unicode
(
language
)
return
HttpResponse
(
200
)
response
.
set_cookie
(
settings
.
LANGUAGE_COOKIE
,
language
,
domain
=
settings
.
SESSION_COOKIE_DOMAIN
,
max_age
=
COOKIE_DURATION
)
return
response
openedx/core/djangoapps/user_api/accounts/tests/test_views.py
View file @
3deb3a3c
...
...
@@ -174,7 +174,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase):
Test that a client (logged in) can get her own username.
"""
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
self
.
_verify_get_own_username
(
1
5
)
self
.
_verify_get_own_username
(
1
4
)
def
test_get_username_inactive
(
self
):
"""
...
...
@@ -184,7 +184,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase):
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
self
.
user
.
is_active
=
False
self
.
user
.
save
()
self
.
_verify_get_own_username
(
1
5
)
self
.
_verify_get_own_username
(
1
4
)
def
test_get_username_not_logged_in
(
self
):
"""
...
...
@@ -305,7 +305,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
self
.
different_client
.
login
(
username
=
self
.
different_user
.
username
,
password
=
TEST_PASSWORD
)
self
.
create_mock_profile
(
self
.
user
)
with
self
.
assertNumQueries
(
1
9
):
with
self
.
assertNumQueries
(
1
8
):
response
=
self
.
send_get
(
self
.
different_client
)
self
.
_verify_full_shareable_account_response
(
response
,
account_privacy
=
ALL_USERS_VISIBILITY
)
...
...
@@ -320,7 +320,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
self
.
different_client
.
login
(
username
=
self
.
different_user
.
username
,
password
=
TEST_PASSWORD
)
self
.
create_mock_profile
(
self
.
user
)
with
self
.
assertNumQueries
(
1
9
):
with
self
.
assertNumQueries
(
1
8
):
response
=
self
.
send_get
(
self
.
different_client
)
self
.
_verify_private_account_response
(
response
,
account_privacy
=
PRIVATE_VISIBILITY
)
...
...
@@ -395,12 +395,12 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
self
.
assertEqual
(
False
,
data
[
"accomplishments_shared"
])
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
verify_get_own_information
(
1
7
)
verify_get_own_information
(
1
6
)
# Now make sure that the user can get the same information, even if not active
self
.
user
.
is_active
=
False
self
.
user
.
save
()
verify_get_own_information
(
1
1
)
verify_get_own_information
(
1
0
)
def
test_get_account_empty_string
(
self
):
"""
...
...
@@ -414,7 +414,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
legacy_profile
.
save
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
with
self
.
assertNumQueries
(
1
7
):
with
self
.
assertNumQueries
(
1
6
):
response
=
self
.
send_get
(
self
.
client
)
for
empty_field
in
(
"level_of_education"
,
"gender"
,
"country"
,
"bio"
):
self
.
assertIsNone
(
response
.
data
[
empty_field
])
...
...
openedx/core/djangoapps/user_api/errors.py
View file @
3deb3a3c
...
...
@@ -83,6 +83,7 @@ class PreferenceValidationError(PreferenceRequestError):
"""
def
__init__
(
self
,
preference_errors
):
self
.
preference_errors
=
preference_errors
super
(
PreferenceValidationError
,
self
)
.
__init__
(
preference_errors
)
class
PreferenceUpdateError
(
PreferenceRequestError
):
...
...
@@ -93,6 +94,7 @@ class PreferenceUpdateError(PreferenceRequestError):
def
__init__
(
self
,
developer_message
,
user_message
=
None
):
self
.
developer_message
=
developer_message
self
.
user_message
=
user_message
super
(
PreferenceUpdateError
,
self
)
.
__init__
(
developer_message
)
class
CountryCodeError
(
ValueError
):
...
...
openedx/core/djangoapps/user_api/helpers.py
View file @
3deb3a3c
...
...
@@ -6,6 +6,7 @@ from collections import defaultdict
from
functools
import
wraps
import
logging
import
json
import
traceback
from
django
import
forms
from
django.core.serializers.json
import
DjangoJSONEncoder
...
...
@@ -65,16 +66,19 @@ def intercept_errors(api_error, ignore_errors=None):
LOGGER
.
warning
(
msg
)
raise
caller
=
traceback
.
format_stack
(
limit
=
2
)[
0
]
# Otherwise, log the error and raise the API-specific error
msg
=
(
u"An unexpected error occurred when calling '{func_name}' "
u"with arguments '{args}' and keyword arguments '{kwargs}': "
u"with arguments '{args}' and keyword arguments '{kwargs}'
from {caller}
: "
u"{exception}"
)
.
format
(
func_name
=
func
.
func_name
,
args
=
args
,
kwargs
=
kwargs
,
exception
=
ex
.
developer_message
if
hasattr
(
ex
,
'developer_message'
)
else
repr
(
ex
)
exception
=
ex
.
developer_message
if
hasattr
(
ex
,
'developer_message'
)
else
repr
(
ex
),
caller
=
caller
.
strip
(),
)
LOGGER
.
exception
(
msg
)
raise
api_error
(
msg
)
...
...
@@ -502,3 +506,13 @@ def shim_student_view(view_func, check_logged_in=False):
return
response
return
_inner
def
serializer_is_dirty
(
preference_serializer
):
"""
Return True if saving the supplied (Raw)UserPreferenceSerializer would change the database.
"""
return
(
preference_serializer
.
instance
is
None
or
preference_serializer
.
instance
.
value
!=
preference_serializer
.
validated_data
[
'value'
]
)
openedx/core/djangoapps/user_api/preferences/api.py
View file @
3deb3a3c
...
...
@@ -20,7 +20,7 @@ from ..errors import (
UserAPIInternalError
,
UserAPIRequestError
,
UserNotFound
,
UserNotAuthorized
,
PreferenceValidationError
,
PreferenceUpdateError
,
CountryCodeError
)
from
..helpers
import
intercept_errors
from
..helpers
import
intercept_errors
,
serializer_is_dirty
from
..models
import
UserOrgTag
,
UserPreference
from
..serializers
import
UserSerializer
,
RawUserPreferenceSerializer
...
...
@@ -142,7 +142,9 @@ def update_user_preferences(requesting_user, update, user=None):
if
preference_value
is
not
None
:
try
:
serializer
=
serializers
[
preference_key
]
serializer
.
save
()
if
serializer_is_dirty
(
serializer
):
serializer
.
save
()
except
Exception
as
error
:
raise
_create_preference_update_error
(
preference_key
,
preference_value
,
error
)
else
:
...
...
@@ -177,10 +179,12 @@ def set_user_preference(requesting_user, preference_key, preference_value, usern
existing_user
=
_get_authorized_user
(
requesting_user
,
username
)
serializer
=
create_user_preference_serializer
(
existing_user
,
preference_key
,
preference_value
)
validate_user_preference_serializer
(
serializer
,
preference_key
,
preference_value
)
try
:
serializer
.
save
()
except
Exception
as
error
:
raise
_create_preference_update_error
(
preference_key
,
preference_value
,
error
)
if
serializer_is_dirty
(
serializer
):
try
:
serializer
.
save
()
except
Exception
as
error
:
raise
_create_preference_update_error
(
preference_key
,
preference_value
,
error
)
@intercept_errors
(
UserAPIInternalError
,
ignore_errors
=
[
UserAPIRequestError
])
...
...
@@ -310,7 +314,13 @@ def _get_authorized_user(requesting_user, username=None, allow_staff=False):
If username is not provided, requesting_user.username is assumed.
"""
if
username
is
None
:
username
=
requesting_user
.
username
# If the user is one that has already been stored to the database, use that
if
requesting_user
.
pk
:
return
requesting_user
else
:
# Otherwise, treat this as a request against a separate user
username
=
requesting_user
.
username
try
:
existing_user
=
User
.
objects
.
get
(
username
=
username
)
except
ObjectDoesNotExist
:
...
...
@@ -347,13 +357,13 @@ def create_user_preference_serializer(user, preference_key, preference_value):
except
ObjectDoesNotExist
:
existing_user_preference
=
None
new_data
=
{
"user"
:
user
.
id
,
"key"
:
preference_key
,
"value"
:
preference_value
,
}
if
existing_user_preference
:
serializer
=
RawUserPreferenceSerializer
(
existing_user_preference
,
data
=
new_data
)
serializer
=
RawUserPreferenceSerializer
(
existing_user_preference
,
data
=
new_data
,
partial
=
True
)
else
:
new_data
[
'user'
]
=
user
.
id
serializer
=
RawUserPreferenceSerializer
(
data
=
new_data
)
return
serializer
...
...
openedx/core/djangoapps/user_api/preferences/tests/test_api.py
View file @
3deb3a3c
...
...
@@ -53,9 +53,8 @@ class TestPreferenceAPI(CacheIsolationTestCase):
super
(
TestPreferenceAPI
,
self
)
.
setUp
()
self
.
user
=
UserFactory
.
create
(
password
=
self
.
password
)
self
.
different_user
=
UserFactory
.
create
(
password
=
self
.
password
)
self
.
staff_user
=
UserFactory
(
is_staff
=
True
,
password
=
self
.
password
)
self
.
no_such_user
=
UserFactory
.
create
(
password
=
self
.
password
)
self
.
no_such_user
.
username
=
"no_such_user"
self
.
staff_user
=
UserFactory
.
create
(
is_staff
=
True
,
password
=
self
.
password
)
self
.
no_such_user
=
UserFactory
.
build
(
password
=
self
.
password
,
username
=
"no_such_user"
)
self
.
test_preference_key
=
"test_key"
self
.
test_preference_value
=
"test_value"
set_user_preference
(
self
.
user
,
self
.
test_preference_key
,
self
.
test_preference_value
)
...
...
openedx/core/djangoapps/user_api/serializers.py
View file @
3deb3a3c
...
...
@@ -22,12 +22,7 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
"""
Return the name attribute from the user profile object if profile exists else none
"""
try
:
profile
=
UserProfile
.
objects
.
get
(
user
=
user
)
except
UserProfile
.
DoesNotExist
:
return
None
return
profile
.
name
return
user
.
profile
.
name
def
get_preferences
(
self
,
user
):
"""
...
...
openedx/core/djangoapps/user_api/tests/test_helpers.py
View file @
3deb3a3c
...
...
@@ -2,6 +2,7 @@
Tests for helper functions.
"""
import
json
import
re
import
mock
import
ddt
from
django
import
forms
...
...
@@ -55,19 +56,31 @@ class InterceptErrorsTest(TestCase):
exception
=
'openedx.core.djangoapps.user_api.tests.test_helpers.FakeInputException'
expected_log_msg
=
(
u"An unexpected error occurred when calling 'intercepted_function' with arguments '()' and "
u"keyword arguments '{'raise_error': <class '"
+
exception
+
u"'>}': FakeInputException()"
)
u"keyword arguments '{{'raise_error': <class '{}'>}}' "
u"from File
\"
{}
\"
, line XXX, in test_logs_errors
\n
"
u" intercepted_function(raise_error=FakeInputException): FakeInputException()"
)
.
format
(
exception
,
__file__
)
# Verify that the raised exception has the error message
try
:
intercepted_function
(
raise_error
=
FakeInputException
)
except
FakeOutputException
as
ex
:
self
.
assertEqual
(
ex
.
message
,
expected_log_msg
)
actual_message
=
re
.
sub
(
r'line \d+'
,
'line XXX'
,
ex
.
message
,
flags
=
re
.
MULTILINE
)
self
.
assertEqual
(
actual_message
,
expected_log_msg
)
# Verify that the error logger is called
# This will include the stack trace for the original exception
# because it's called with log level "ERROR"
mock_logger
.
exception
.
assert_called_once_with
(
expected_log_msg
)
calls
=
mock_logger
.
exception
.
mock_calls
self
.
assertEqual
(
len
(
calls
),
1
)
name
,
args
,
kwargs
=
calls
[
0
]
self
.
assertEqual
(
name
,
''
)
self
.
assertEqual
(
len
(
args
),
1
)
self
.
assertEqual
(
kwargs
,
{})
actual_message
=
re
.
sub
(
r'line \d+'
,
'line XXX'
,
args
[
0
],
flags
=
re
.
MULTILINE
)
self
.
assertEqual
(
actual_message
,
expected_log_msg
)
class
FormDescriptionTest
(
TestCase
):
...
...
openedx/core/djangoapps/user_api/views.py
View file @
3deb3a3c
...
...
@@ -1002,7 +1002,7 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
authentication_classes
=
(
authentication
.
SessionAuthentication
,)
permission_classes
=
(
ApiKeyHeaderPermission
,)
queryset
=
User
.
objects
.
all
()
.
prefetch_related
(
"preferences"
)
queryset
=
User
.
objects
.
all
()
.
prefetch_related
(
"preferences"
)
.
select_related
(
"profile"
)
serializer_class
=
UserSerializer
paginate_by
=
10
paginate_by_param
=
"page_size"
...
...
@@ -1028,7 +1028,7 @@ class ForumRoleUsersListView(generics.ListAPIView):
raise
ParseError
(
'course_id must be specified'
)
course_id
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id_string
)
role
=
Role
.
objects
.
get_or_create
(
course_id
=
course_id
,
name
=
name
)[
0
]
users
=
role
.
users
.
all
()
users
=
role
.
users
.
prefetch_related
(
"preferences"
)
.
select_related
(
"profile"
)
.
all
()
return
users
...
...
@@ -1057,7 +1057,7 @@ class PreferenceUsersListView(generics.ListAPIView):
paginate_by_param
=
"page_size"
def
get_queryset
(
self
):
return
User
.
objects
.
filter
(
preferences__key
=
self
.
kwargs
[
"pref_key"
])
.
prefetch_related
(
"preferences"
)
return
User
.
objects
.
filter
(
preferences__key
=
self
.
kwargs
[
"pref_key"
])
.
prefetch_related
(
"preferences"
)
.
select_related
(
"profile"
)
class
UpdateEmailOptInPreference
(
APIView
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment