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
ab912fa8
Commit
ab912fa8
authored
May 15, 2015
by
Muzaffar yousaf
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7956 from edx/muzaffar/tnl2047-profile-tweaks
Learner Profile page tweaks.
parents
36060f3f
cae5623f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
76 additions
and
143 deletions
+76
-143
common/test/acceptance/tests/lms/test_learner_profile.py
+1
-1
lms/djangoapps/student_account/views.py
+1
-8
lms/djangoapps/student_profile/test/test_views.py
+6
-1
lms/djangoapps/student_profile/views.py
+27
-18
lms/static/js/spec/student_profile/learner_profile_factory_spec.js
+11
-67
lms/static/js/student_account/models/user_account_model.js
+2
-2
lms/static/js/student_profile/views/learner_profile_factory.js
+17
-31
lms/static/js/views/fields.js
+5
-1
lms/static/sass/views/_learner-profile.scss
+0
-1
lms/templates/register.html
+1
-1
lms/templates/student_profile/learner_profile.html
+2
-1
openedx/core/djangoapps/user_api/tests/test_constants.py
+0
-0
openedx/core/djangoapps/user_api/views.py
+1
-10
requirements/edx/base.txt
+2
-1
No files found.
common/test/acceptance/tests/lms/test_learner_profile.py
View file @
ab912fa8
...
...
@@ -47,7 +47,7 @@ class LearnerProfileTestMixin(EventsTestMixin):
Fill in the public profile fields of a user.
"""
profile_page
.
value_for_dropdown_field
(
'language_proficiencies'
,
'English'
)
profile_page
.
value_for_dropdown_field
(
'country'
,
'United
Kingdom
'
)
profile_page
.
value_for_dropdown_field
(
'country'
,
'United
Arab Emirates
'
)
profile_page
.
value_for_textarea_field
(
'bio'
,
'Nothing Special'
)
def
visit_profile_page
(
self
,
username
,
privacy
=
None
):
...
...
lms/djangoapps/student_account/views.py
View file @
ab912fa8
...
...
@@ -338,13 +338,6 @@ def account_settings_context(request):
"""
user
=
request
.
user
country_options
=
[
(
country_code
,
_
(
country_name
))
# pylint: disable=translation-of-non-string
for
country_code
,
country_name
in
sorted
(
countries
.
countries
,
key
=
lambda
(
__
,
name
):
unicode
(
name
)
)
]
year_of_birth_options
=
[(
unicode
(
year
),
unicode
(
year
))
for
year
in
UserProfile
.
VALID_YEARS
]
context
=
{
...
...
@@ -352,7 +345,7 @@ def account_settings_context(request):
'duplicate_provider'
:
None
,
'fields'
:
{
'country'
:
{
'options'
:
country_options
,
'options'
:
list
(
countries
)
,
},
'gender'
:
{
'options'
:
[(
choice
[
0
],
_
(
choice
[
1
]))
for
choice
in
UserProfile
.
GENDER_CHOICES
],
# pylint: disable=translation-of-non-string
},
'language'
:
{
...
...
lms/djangoapps/student_profile/test/test_views.py
View file @
ab912fa8
...
...
@@ -4,6 +4,7 @@
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django.test.client
import
RequestFactory
from
util.testing
import
UrlResetMixin
from
student.tests.factories
import
UserFactory
...
...
@@ -25,6 +26,8 @@ class LearnerProfileViewTest(UrlResetMixin, TestCase):
'own_profile'
,
'country_options'
,
'language_options'
,
'account_settings_data'
,
'preferences_data'
,
]
def
setUp
(
self
):
...
...
@@ -36,7 +39,9 @@ class LearnerProfileViewTest(UrlResetMixin, TestCase):
"""
Verify learner profile page context data.
"""
context
=
learner_profile_context
(
self
.
user
.
username
,
self
.
USERNAME
,
self
.
user
.
is_staff
)
request
=
RequestFactory
()
.
get
(
'/url'
)
context
=
learner_profile_context
(
self
.
user
,
self
.
USERNAME
,
self
.
user
.
is_staff
,
request
.
build_absolute_uri
)
self
.
assertEqual
(
context
[
'data'
][
'default_public_account_fields'
],
...
...
lms/djangoapps/student_profile/views.py
View file @
ab912fa8
...
...
@@ -6,12 +6,15 @@ from django_countries import countries
from
django.core.urlresolvers
import
reverse
from
django.contrib.auth.decorators
import
login_required
from
django.http
import
Http
Response
from
django.http
import
Http
404
from
django.views.decorators.http
import
require_http_methods
from
edxmako.shortcuts
import
render_to_response
from
openedx.core.djangoapps.user_api.accounts.api
import
get_account_settings
from
openedx.core.djangoapps.user_api.accounts.serializers
import
PROFILE_IMAGE_KEY_PREFIX
from
openedx.core.djangoapps.user_api.errors
import
UserNotFound
,
UserNotAuthorized
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preferences
from
student.models
import
User
from
microsite_configuration
import
microsite
from
django.utils.translation
import
ugettext
as
_
...
...
@@ -29,8 +32,9 @@ def learner_profile(request, username):
Returns:
HttpResponse: 200 if the page was sent successfully
HttpResponse: 302 if not logged in (redirect to login page)
HttpResponse: 404 if the specified username does not exist
HttpResponse: 405 if using an unsupported HTTP method
Raises:
Http404: 404 if the specified user is not authorized or does not exist
Example usage:
GET /account/profile
...
...
@@ -38,19 +42,20 @@ def learner_profile(request, username):
try
:
return
render_to_response
(
'student_profile/learner_profile.html'
,
learner_profile_context
(
request
.
user
.
username
,
username
,
request
.
user
.
is_staff
)
learner_profile_context
(
request
.
user
,
username
,
request
.
user
.
is_staff
,
request
.
build_absolute_uri
)
)
except
ObjectDoesNotExist
:
r
eturn
HttpResponse
(
status
=
404
)
except
(
UserNotAuthorized
,
UserNotFound
,
ObjectDoesNotExist
)
:
r
aise
Http404
def
learner_profile_context
(
logged_in_user
name
,
profile_username
,
user_is_staff
):
def
learner_profile_context
(
logged_in_user
,
profile_username
,
user_is_staff
,
build_absolute_uri_func
):
"""Context for the learner profile page.
Args:
logged_in_user
name (str): Username of user l
ogged In user.
logged_in_user
(object): L
ogged In user.
profile_username (str): username of user whose profile is requested.
user_is_staff (bool): Logged In user has staff access.
build_absolute_uri_func ():
Returns:
dict
...
...
@@ -60,12 +65,15 @@ def learner_profile_context(logged_in_username, profile_username, user_is_staff)
"""
profile_user
=
User
.
objects
.
get
(
username
=
profile_username
)
country_options
=
[
(
country_code
,
_
(
country_name
))
# pylint: disable=translation-of-non-string
for
country_code
,
country_name
in
sorted
(
countries
.
countries
,
key
=
lambda
(
__
,
name
):
unicode
(
name
)
)
]
own_profile
=
(
logged_in_user
.
username
==
profile_username
)
account_settings_data
=
get_account_settings
(
logged_in_user
,
profile_username
)
# Account for possibly relative URLs.
for
key
,
value
in
account_settings_data
[
'profile_image'
]
.
items
():
if
key
.
startswith
(
PROFILE_IMAGE_KEY_PREFIX
):
account_settings_data
[
'profile_image'
][
key
]
=
build_absolute_uri_func
(
value
)
preferences_data
=
get_user_preferences
(
profile_user
,
profile_username
)
context
=
{
'data'
:
{
...
...
@@ -74,17 +82,18 @@ def learner_profile_context(logged_in_username, profile_username, user_is_staff)
'default_visibility'
:
settings
.
ACCOUNT_VISIBILITY_CONFIGURATION
[
'default_visibility'
],
'accounts_api_url'
:
reverse
(
"accounts_api"
,
kwargs
=
{
'username'
:
profile_username
}),
'preferences_api_url'
:
reverse
(
'preferences_api'
,
kwargs
=
{
'username'
:
profile_username
}),
'preferences_data'
:
preferences_data
,
'account_settings_data'
:
account_settings_data
,
'profile_image_upload_url'
:
reverse
(
'profile_image_upload'
,
kwargs
=
{
'username'
:
profile_username
}),
'profile_image_remove_url'
:
reverse
(
'profile_image_remove'
,
kwargs
=
{
'username'
:
profile_username
}),
'profile_image_max_bytes'
:
settings
.
PROFILE_IMAGE_MAX_BYTES
,
'profile_image_min_bytes'
:
settings
.
PROFILE_IMAGE_MIN_BYTES
,
'account_settings_page_url'
:
reverse
(
'account_settings'
),
'has_preferences_access'
:
(
logged_in_username
==
profile_username
or
user_is_staff
),
'own_profile'
:
(
logged_in_username
==
profile_username
)
,
'country_options'
:
country_options
,
'has_preferences_access'
:
(
logged_in_user
.
user
name
==
profile_username
or
user_is_staff
),
'own_profile'
:
own_profile
,
'country_options'
:
list
(
countries
)
,
'language_options'
:
settings
.
ALL_LANGUAGES
,
'platform_name'
:
microsite
.
get_value
(
'platform_name'
,
settings
.
PLATFORM_NAME
),
}
}
return
context
lms/static/js/spec/student_profile/learner_profile_factory_spec.js
View file @
ab912fa8
...
...
@@ -27,7 +27,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
TemplateHelpers
.
installTemplate
(
'templates/student_profile/learner_profile'
);
});
var
createProfilePage
=
function
(
ownProfile
)
{
var
createProfilePage
=
function
(
ownProfile
,
options
)
{
return
new
LearnerProfilePage
({
'accounts_api_url'
:
Helpers
.
USER_ACCOUNTS_API_URL
,
'preferences_api_url'
:
Helpers
.
USER_PREFERENCES_API_URL
,
...
...
@@ -41,55 +41,13 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
'profile_image_upload_url'
:
Helpers
.
IMAGE_UPLOAD_API_URL
,
'profile_image_remove_url'
:
Helpers
.
IMAGE_REMOVE_API_URL
,
'default_visibility'
:
'all_users'
,
'platform_name'
:
'edX'
'platform_name'
:
'edX'
,
'account_settings_data'
:
Helpers
.
createAccountSettingsData
(
options
),
'preferences_data'
:
Helpers
.
createUserPreferencesData
()
});
};
it
(
"show loading error when UserAccountModel fails to load"
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
var
context
=
createProfilePage
(
true
),
learnerProfileView
=
context
.
learnerProfileView
;
var
userAccountRequest
=
requests
[
0
];
expect
(
userAccountRequest
.
method
).
toBe
(
'GET'
);
expect
(
userAccountRequest
.
url
).
toBe
(
Helpers
.
USER_ACCOUNTS_API_URL
);
AjaxHelpers
.
respondWithError
(
requests
,
500
);
Helpers
.
expectLoadingErrorIsVisible
(
learnerProfileView
,
true
);
Helpers
.
expectLoadingIndicatorIsVisible
(
learnerProfileView
,
false
);
LearnerProfileHelpers
.
expectProfileSectionsNotToBeRendered
(
learnerProfileView
);
});
it
(
"shows loading error when UserPreferencesModel fails to load"
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
var
context
=
createProfilePage
(
true
),
learnerProfileView
=
context
.
learnerProfileView
;
var
userAccountRequest
=
requests
[
0
];
expect
(
userAccountRequest
.
method
).
toBe
(
'GET'
);
expect
(
userAccountRequest
.
url
).
toBe
(
Helpers
.
USER_ACCOUNTS_API_URL
);
AjaxHelpers
.
respondWithJson
(
requests
,
Helpers
.
createAccountSettingsData
());
Helpers
.
expectLoadingIndicatorIsVisible
(
learnerProfileView
,
true
);
Helpers
.
expectLoadingErrorIsVisible
(
learnerProfileView
,
false
);
LearnerProfileHelpers
.
expectProfileSectionsNotToBeRendered
(
learnerProfileView
);
var
userPreferencesRequest
=
requests
[
1
];
expect
(
userPreferencesRequest
.
method
).
toBe
(
'GET'
);
expect
(
userPreferencesRequest
.
url
).
toBe
(
Helpers
.
USER_PREFERENCES_API_URL
);
AjaxHelpers
.
respondWithError
(
requests
,
500
);
Helpers
.
expectLoadingIndicatorIsVisible
(
learnerProfileView
,
false
);
Helpers
.
expectLoadingErrorIsVisible
(
learnerProfileView
,
true
);
LearnerProfileHelpers
.
expectProfileSectionsNotToBeRendered
(
learnerProfileView
);
});
it
(
"renders the full profile after models are successfully fetched"
,
function
()
{
it
(
"renders the full profile after data is successfully fetched"
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
...
...
@@ -106,33 +64,19 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
it
(
"renders the limited profile for undefined 'year_of_birth'"
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
var
context
=
createProfilePage
(
true
),
var
context
=
createProfilePage
(
true
,
{
year_of_birth
:
''
,
requires_parental_consent
:
true
}),
learnerProfileView
=
context
.
learnerProfileView
;
AjaxHelpers
.
respondWithJson
(
requests
,
Helpers
.
createAccountSettingsData
({
year_of_birth
:
''
,
requires_parental_consent
:
true
}));
AjaxHelpers
.
respondWithJson
(
requests
,
Helpers
.
createUserPreferencesData
());
LearnerProfileHelpers
.
expectLimitedProfileSectionsAndFieldsToBeRendered
(
learnerProfileView
);
});
it
(
"renders the limited profile for under 13 users"
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
var
context
=
createProfilePage
(
true
),
learnerProfileView
=
context
.
learnerProfileView
;
AjaxHelpers
.
respondWithJson
(
requests
,
Helpers
.
createAccountSettingsData
({
year_of_birth
:
new
Date
().
getFullYear
()
-
10
,
requires_parental_consent
:
true
}));
AjaxHelpers
.
respondWithJson
(
requests
,
Helpers
.
createUserPreferencesData
());
var
context
=
createProfilePage
(
true
,
{
year_of_birth
:
new
Date
().
getFullYear
()
-
10
,
requires_parental_consent
:
true
}
);
var
learnerProfileView
=
context
.
learnerProfileView
;
LearnerProfileHelpers
.
expectLimitedProfileSectionsAndFieldsToBeRendered
(
learnerProfileView
);
});
});
...
...
lms/static/js/student_account/models/user_account_model.js
View file @
ab912fa8
...
...
@@ -34,8 +34,8 @@
// Currently when a non-staff user A access user B's profile, the only way to tell whether user B's
// profile is public is to check if the api has returned fields other than the default public fields
// specified in settings.ACCOUNT_VISIBILITY_CONFIGURATION.
var
profileIsPublic
=
_
.
size
(
_
.
difference
(
_
.
keys
(
response
),
this
.
get
(
'default_public_account_fields'
)))
>
0
;
this
.
set
({
'profile_is_public'
:
profileIsPublic
},
{
silent
:
true
})
;
var
responseKeys
=
_
.
filter
(
_
.
keys
(
response
),
function
(
key
)
{
return
key
!==
'default_public_account_fields'
})
;
response
.
profile_is_public
=
_
.
size
(
_
.
difference
(
responseKeys
,
response
.
default_public_account_fields
))
>
0
;
return
response
;
},
...
...
lms/static/js/student_profile/views/learner_profile_factory.js
View file @
ab912fa8
...
...
@@ -15,19 +15,23 @@
return
function
(
options
)
{
var
learnerProfileElement
=
$
(
'.wrapper-profile'
);
var
defaultVisibility
=
options
.
default_visibility
;
var
accountSettingsModel
=
new
AccountSettingsModel
(
_
.
extend
(
options
.
account_settings_data
,
{
'default_public_account_fields'
:
options
.
default_public_account_fields
}
),
{
parse
:
true
}
);
var
AccountPreferencesModelWithDefaults
=
AccountPreferencesModel
.
extend
({
defaults
:
{
account_privacy
:
defaultV
isibility
account_privacy
:
options
.
default_v
isibility
}
});
var
accountPreferencesModel
=
new
AccountPreferencesModelWithDefaults
();
accountPreferencesModel
.
url
=
options
.
preferences_api_url
;
var
accountPreferencesModel
=
new
AccountPreferencesModelWithDefaults
(
options
.
preferences_data
);
var
accountSettingsModel
=
new
AccountSettingsModel
({
'default_public_account_fields'
:
options
.
default_public_account_fields
});
accountSettingsModel
.
url
=
options
.
accounts_api_url
;
accountPreferencesModel
.
url
=
options
.
preferences_api_url
;
var
editable
=
options
.
own_profile
?
'toggle'
:
'never'
;
...
...
@@ -122,10 +126,6 @@
sectionTwoFieldViews
:
sectionTwoFieldViews
});
var
showLoadingError
=
function
()
{
learnerProfileView
.
showLoadingError
();
};
var
getProfileVisibility
=
function
()
{
if
(
options
.
has_preferences_access
)
{
return
accountPreferencesModel
.
get
(
'account_privacy'
);
...
...
@@ -146,26 +146,12 @@
learnerProfileView
.
render
();
};
accountSettingsModel
.
fetch
({
success
:
function
()
{
// Fetch the preferences model if the user has access
if
(
options
.
has_preferences_access
)
{
accountPreferencesModel
.
fetch
({
success
:
function
()
{
if
(
accountSettingsModel
.
get
(
'requires_parental_consent'
))
{
accountPreferencesModel
.
set
(
'account_privacy'
,
'private'
);
}
showLearnerProfileView
();
},
error
:
showLoadingError
});
}
else
{
showLearnerProfileView
();
}
},
error
:
showLoadingError
});
if
(
options
.
has_preferences_access
)
{
if
(
accountSettingsModel
.
get
(
'requires_parental_consent'
))
{
accountPreferencesModel
.
set
(
'account_privacy'
,
'private'
);
}
}
showLearnerProfileView
();
return
{
accountSettingsModel
:
accountSettingsModel
,
...
...
lms/static/js/views/fields.js
View file @
ab912fa8
...
...
@@ -114,7 +114,11 @@
setTimeout
(
function
()
{
if
((
context
===
view
.
lastSuccessMessageContext
)
&&
(
view
.
getNotificationMessage
()
===
successMessage
))
{
view
.
showHelpMessage
();
if
(
view
.
editable
===
'toggle'
)
{
view
.
showCanEditMessage
(
true
);
}
else
{
view
.
showHelpMessage
();
}
}
},
messageRevertDelay
);
},
...
...
lms/static/sass/views/_learner-profile.scss
View file @
ab912fa8
...
...
@@ -218,7 +218,6 @@
.wrapper-profile-section-two
{
width
:
flex-grid
(
8
,
12
);
margin-top
:
(
$baseline
*
1
.5
);
}
.profile-section-two-fields
{
...
...
lms/templates/register.html
View file @
ab912fa8
...
...
@@ -256,7 +256,7 @@
<label
for=
"country"
>
${_("Country")}
</label>
<select
id=
"country"
name=
"country"
${'
required
aria-required=
"true"
'
if
settings
.
REGISTRATION_EXTRA_FIELDS
['
country
']
==
'
required
'
else
''}
>
<option
value=
""
>
--
</option>
%for code, country_name in
sorted(countries.countries, key=lambda (__, name): unicode(name))
:
%for code, country_name in
countries
:
<option
value=
"${code}"
>
${ unicode(country_name) }
</option>
%endfor
</select>
...
...
lms/templates/student_profile/learner_profile.html
View file @
ab912fa8
<
%!
import
json
%
>
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%!
from
xmodule
.
modulestore
import
EdxJSONEncoder
%
>
<
%
inherit
file=
"/main.html"
/>
<
%
namespace
name=
'static'
file=
'/static_content.html'
/>
...
...
@@ -38,7 +39,7 @@
<script>
(
function
(
require
)
{
require
([
'js/student_profile/views/learner_profile_factory'
],
function
(
setupLearnerProfile
)
{
var
options
=
$
{
json
.
dumps
(
data
)
};
var
options
=
$
{
json
.
dumps
(
data
,
cls
=
EdxJSONEncoder
)
};
setupLearnerProfile
(
options
);
});
}).
call
(
this
,
require
||
RequireJS
.
require
);
...
...
openedx/core/djangoapps/user_api/tests/test_constants.py
View file @
ab912fa8
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/user_api/views.py
View file @
ab912fa8
...
...
@@ -581,22 +581,13 @@ class RegistrationView(APIView):
# Translators: This label appears above a dropdown menu on the registration
# form used to select the country in which the user lives.
country_label
=
_
(
u"Country"
)
sorted_countries
=
sorted
(
countries
.
countries
,
key
=
lambda
(
__
,
name
):
unicode
(
name
)
)
options
=
[
(
country_code
,
unicode
(
country_name
))
for
country_code
,
country_name
in
sorted_countries
]
error_msg
=
_
(
u"Please select your Country."
)
form_desc
.
add_field
(
"country"
,
label
=
country_label
,
field_type
=
"select"
,
options
=
options
,
options
=
list
(
countries
)
,
include_default_option
=
True
,
required
=
required
,
error_messages
=
{
...
...
requirements/edx/base.txt
View file @
ab912fa8
...
...
@@ -16,7 +16,7 @@ defusedxml==0.4.1
distribute>=0.6.28, <0.7
django-babel-underscore==0.1.0
django-celery==3.1.16
django-countries==
2.1.2
django-countries==
3.3
django-extensions==1.2.5
django-filter==0.6.0
django-followit==0.0.3
...
...
@@ -88,6 +88,7 @@ xmltodict==0.4.1
django-ratelimit-backend==0.6
unicodecsv==0.9.4
django-require==1.0.6
pyuca==1.1
# Used for shopping cart's pdf invoice/receipt generation
reportlab==3.1.44
...
...
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