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
af299af1
Commit
af299af1
authored
May 05, 2014
by
Matt Drayer
Committed by
Jonathan Piacenti
Aug 20, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mattdrayer/CLIENT-932: API - Enables editing of User data
parent
1e1c05c4
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
69 additions
and
59 deletions
+69
-59
lms/djangoapps/api_manager/sessions/tests.py
+1
-1
lms/djangoapps/api_manager/sessions/views.py
+3
-3
lms/djangoapps/api_manager/users/test_user_password_reset.py
+8
-14
lms/djangoapps/api_manager/users/tests.py
+26
-9
lms/djangoapps/api_manager/users/views.py
+31
-32
No files found.
lms/djangoapps/api_manager/sessions/tests.py
View file @
af299af1
...
@@ -143,7 +143,7 @@ class SessionsApiTests(TestCase):
...
@@ -143,7 +143,7 @@ class SessionsApiTests(TestCase):
data
=
{
'username'
:
local_username
,
'password'
:
self
.
test_password
}
data
=
{
'username'
:
local_username
,
'password'
:
self
.
test_password
}
response
=
self
.
do_post
(
self
.
base_sessions_uri
,
data
)
response
=
self
.
do_post
(
self
.
base_sessions_uri
,
data
)
self
.
assertEqual
(
response
.
status_code
,
201
)
self
.
assertEqual
(
response
.
status_code
,
201
)
test_uri
=
self
.
base_
users_uri
+
str
(
response
.
data
[
'user'
][
'id
'
])
test_uri
=
self
.
base_
sessions_uri
+
str
(
response
.
data
[
'token
'
])
response
=
self
.
do_delete
(
test_uri
)
response
=
self
.
do_delete
(
test_uri
)
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assertEqual
(
response
.
status_code
,
204
)
response
=
self
.
do_get
(
test_uri
)
response
=
self
.
do_get
(
test_uri
)
...
...
lms/djangoapps/api_manager/sessions/views.py
View file @
af299af1
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
import
logging
import
logging
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth
import
authenticate
,
login
from
django.contrib.auth
import
authenticate
,
login
,
logout
from
django.contrib.auth
import
SESSION_KEY
,
BACKEND_SESSION_KEY
,
load_backend
from
django.contrib.auth
import
SESSION_KEY
,
BACKEND_SESSION_KEY
,
load_backend
from
django.contrib.auth.models
import
AnonymousUser
,
User
from
django.contrib.auth.models
import
AnonymousUser
,
User
from
django.core.exceptions
import
ObjectDoesNotExist
from
django.core.exceptions
import
ObjectDoesNotExist
...
@@ -151,4 +151,5 @@ class SessionsDetail(APIView):
...
@@ -151,4 +151,5 @@ class SessionsDetail(APIView):
user_id
=
session
[
SESSION_KEY
]
user_id
=
session
[
SESSION_KEY
]
AUDIT_LOG
.
info
(
u"API::User session terminated for user-id - {0}"
.
format
(
user_id
))
AUDIT_LOG
.
info
(
u"API::User session terminated for user-id - {0}"
.
format
(
user_id
))
session
.
flush
()
session
.
flush
()
return
Response
(
response_data
,
status
=
status
.
HTTP_204_NO_CONTENT
)
logout
(
request
)
\ No newline at end of file
return
Response
(
response_data
,
status
=
status
.
HTTP_204_NO_CONTENT
)
lms/djangoapps/api_manager/users/test_user_password_reset.py
View file @
af299af1
...
@@ -63,7 +63,7 @@ class UserPasswordResetTest(TestCase):
...
@@ -63,7 +63,7 @@ class UserPasswordResetTest(TestCase):
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
)
)
self
.
assertEqual
(
response
.
status_code
,
20
1
)
self
.
assertEqual
(
response
.
status_code
,
20
0
)
#login successful after reset password
#login successful after reset password
response
=
self
.
_do_post_request
(
self
.
session_url
,
'test2'
,
'Test.Me64@'
,
secure
=
True
)
response
=
self
.
_do_post_request
(
self
.
session_url
,
'test2'
,
'Test.Me64@'
,
secure
=
True
)
...
@@ -88,20 +88,17 @@ class UserPasswordResetTest(TestCase):
...
@@ -88,20 +88,17 @@ class UserPasswordResetTest(TestCase):
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64#'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64#'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64^'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64^'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
#now use previously used password
#now use previously used password
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
...
@@ -116,15 +113,13 @@ class UserPasswordResetTest(TestCase):
...
@@ -116,15 +113,13 @@ class UserPasswordResetTest(TestCase):
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64&'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64&'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
#now use previously used password
#now use previously used password
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64!'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64!'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
@override_settings
(
ADVANCED_SECURITY_CONFIG
=
{
'MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'
:
1
})
@override_settings
(
ADVANCED_SECURITY_CONFIG
=
{
'MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'
:
1
})
def
test_is_password_reset_too_frequent
(
self
):
def
test_is_password_reset_too_frequent
(
self
):
...
@@ -154,8 +149,7 @@ class UserPasswordResetTest(TestCase):
...
@@ -154,8 +149,7 @@ class UserPasswordResetTest(TestCase):
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'NewP@ses34!'
,
secure
=
True
pass_reset_url
,
password
=
'NewP@ses34!'
,
secure
=
True
)
)
message
=
'Password Reset Successful'
self
.
_assert_response
(
response
,
status
=
200
)
self
.
_assert_response
(
response
,
status
=
201
,
message
=
message
)
@override_settings
(
ADVANCED_SECURITY_CONFIG
=
{
'MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'
:
0
})
@override_settings
(
ADVANCED_SECURITY_CONFIG
=
{
'MIN_TIME_IN_DAYS_BETWEEN_ALLOWED_RESETS'
:
0
})
def
test_password_reset_rate_limiting_unblock
(
self
):
def
test_password_reset_rate_limiting_unblock
(
self
):
...
@@ -191,7 +185,7 @@ class UserPasswordResetTest(TestCase):
...
@@ -191,7 +185,7 @@ class UserPasswordResetTest(TestCase):
response
=
self
.
_do_post_pass_reset_request
(
response
=
self
.
_do_post_pass_reset_request
(
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
pass_reset_url
,
password
=
'Test.Me64@'
,
secure
=
True
)
)
self
.
_assert_response
(
response
,
status
=
20
1
)
self
.
_assert_response
(
response
,
status
=
20
0
)
def
_do_post_request
(
self
,
url
,
username
,
password
,
**
kwargs
):
def
_do_post_request
(
self
,
url
,
username
,
password
,
**
kwargs
):
"""
"""
...
...
lms/djangoapps/api_manager/users/tests.py
View file @
af299af1
...
@@ -87,6 +87,15 @@ class UsersApiTests(TestCase):
...
@@ -87,6 +87,15 @@ class UsersApiTests(TestCase):
self
.
assertEqual
(
response
.
data
[
'first_name'
],
self
.
test_first_name
)
self
.
assertEqual
(
response
.
data
[
'first_name'
],
self
.
test_first_name
)
self
.
assertEqual
(
response
.
data
[
'last_name'
],
self
.
test_last_name
)
self
.
assertEqual
(
response
.
data
[
'last_name'
],
self
.
test_last_name
)
def
test_user_list_post_inactive
(
self
):
test_uri
=
'/api/users'
local_username
=
self
.
test_username
+
str
(
randint
(
11
,
99
))
data
=
{
'email'
:
self
.
test_email
,
'username'
:
local_username
,
'password'
:
self
.
test_password
,
'first_name'
:
self
.
test_first_name
,
'last_name'
:
self
.
test_last_name
,
'is_active'
:
False
}
response
=
self
.
do_post
(
test_uri
,
data
)
self
.
assertEqual
(
response
.
status_code
,
201
)
self
.
assertEqual
(
response
.
data
[
'is_active'
],
False
)
def
test_user_list_post_duplicate
(
self
):
def
test_user_list_post_duplicate
(
self
):
test_uri
=
'/api/users'
test_uri
=
'/api/users'
local_username
=
self
.
test_username
+
str
(
randint
(
11
,
99
))
local_username
=
self
.
test_username
+
str
(
randint
(
11
,
99
))
...
@@ -112,24 +121,32 @@ class UsersApiTests(TestCase):
...
@@ -112,24 +121,32 @@ class UsersApiTests(TestCase):
self
.
assertEqual
(
response
.
data
[
'username'
],
local_username
)
self
.
assertEqual
(
response
.
data
[
'username'
],
local_username
)
self
.
assertEqual
(
response
.
data
[
'first_name'
],
self
.
test_first_name
)
self
.
assertEqual
(
response
.
data
[
'first_name'
],
self
.
test_first_name
)
self
.
assertEqual
(
response
.
data
[
'last_name'
],
self
.
test_last_name
)
self
.
assertEqual
(
response
.
data
[
'last_name'
],
self
.
test_last_name
)
self
.
assertEqual
(
response
.
data
[
'is_active'
],
True
)
self
.
assertEqual
(
len
(
response
.
data
[
'resources'
]),
2
)
self
.
assertEqual
(
len
(
response
.
data
[
'resources'
]),
2
)
def
test_user_detail_delete
(
self
):
def
test_user_detail_get_undefined
(
self
):
test_uri
=
'/api/users/123456789'
response
=
self
.
do_get
(
test_uri
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_user_detail_post
(
self
):
test_uri
=
'/api/users'
test_uri
=
'/api/users'
local_username
=
self
.
test_username
+
str
(
randint
(
11
,
99
))
local_username
=
self
.
test_username
+
str
(
randint
(
11
,
99
))
data
=
{
'email'
:
self
.
test_email
,
'username'
:
local_username
,
'password'
:
self
.
test_password
,
'first_name'
:
self
.
test_first_name
,
'last_name'
:
self
.
test_last_name
}
data
=
{
'email'
:
self
.
test_email
,
'username'
:
local_username
,
'password'
:
self
.
test_password
,
'first_name'
:
self
.
test_first_name
,
'last_name'
:
self
.
test_last_name
}
response
=
self
.
do_post
(
test_uri
,
data
)
response
=
self
.
do_post
(
test_uri
,
data
)
test_uri
=
test_uri
+
'/'
+
str
(
response
.
data
[
'id'
])
test_uri
=
test_uri
+
'/'
+
str
(
response
.
data
[
'id'
])
response
=
self
.
do_delete
(
test_uri
)
data
=
{
'is_active'
:
False
}
self
.
assertEqual
(
response
.
status_code
,
204
)
response
=
self
.
do_post
(
test_uri
,
data
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
data
[
'is_active'
],
False
)
response
=
self
.
do_get
(
test_uri
)
response
=
self
.
do_get
(
test_uri
)
self
.
assertEqual
(
response
.
status_code
,
404
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response
=
self
.
do_delete
(
test_uri
)
# User no longer exists, should get a 204 all the same
self
.
assertEqual
(
response
.
data
[
'is_active'
],
False
)
self
.
assertEqual
(
response
.
status_code
,
204
)
def
test_user_detail_get_undefined
(
self
):
def
test_user_detail_post_invalid_user
(
self
):
test_uri
=
'/api/users/123456789'
test_uri
=
'/api/users/123124124'
response
=
self
.
do_get
(
test_uri
)
data
=
{
'is_active'
:
False
}
response
=
self
.
do_post
(
test_uri
,
data
)
self
.
assertEqual
(
response
.
status_code
,
404
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_user_groups_list_post
(
self
):
def
test_user_groups_list_post
(
self
):
...
...
lms/djangoapps/api_manager/users/views.py
View file @
af299af1
...
@@ -54,6 +54,7 @@ def _serialize_user(response_data, user):
...
@@ -54,6 +54,7 @@ def _serialize_user(response_data, user):
response_data
[
'first_name'
]
=
user
.
first_name
response_data
[
'first_name'
]
=
user
.
first_name
response_data
[
'last_name'
]
=
user
.
last_name
response_data
[
'last_name'
]
=
user
.
last_name
response_data
[
'id'
]
=
user
.
id
response_data
[
'id'
]
=
user
.
id
response_data
[
'is_active'
]
=
user
.
is_active
return
response_data
return
response_data
def
_save_module_position
(
request
,
user
,
course_id
,
course_descriptor
,
position
):
def
_save_module_position
(
request
,
user
,
course_id
,
course_descriptor
,
position
):
...
@@ -104,6 +105,7 @@ class UsersList(APIView):
...
@@ -104,6 +105,7 @@ class UsersList(APIView):
password
=
request
.
DATA
[
'password'
]
password
=
request
.
DATA
[
'password'
]
first_name
=
request
.
DATA
.
get
(
'first_name'
,
''
)
first_name
=
request
.
DATA
.
get
(
'first_name'
,
''
)
last_name
=
request
.
DATA
.
get
(
'last_name'
,
''
)
last_name
=
request
.
DATA
.
get
(
'last_name'
,
''
)
is_active
=
request
.
DATA
.
get
(
'is_active'
,
None
)
# enforce password complexity as an optional feature
# enforce password complexity as an optional feature
if
settings
.
FEATURES
.
get
(
'ENFORCE_PASSWORD_POLICY'
,
False
):
if
settings
.
FEATURES
.
get
(
'ENFORCE_PASSWORD_POLICY'
,
False
):
...
@@ -138,12 +140,14 @@ class UsersList(APIView):
...
@@ -138,12 +140,14 @@ class UsersList(APIView):
user
.
set_password
(
password
)
user
.
set_password
(
password
)
user
.
first_name
=
first_name
user
.
first_name
=
first_name
user
.
last_name
=
last_name
user
.
last_name
=
last_name
if
is_active
is
not
None
:
user
.
is_active
=
is_active
user
.
save
()
user
.
save
()
profile
=
UserProfile
(
user
=
user
)
profile
=
UserProfile
(
user
=
user
)
profile
.
name
=
'{} {}'
.
format
(
first_name
,
last_name
)
profile
.
name
=
'{} {}'
.
format
(
first_name
,
last_name
)
profile
.
save
()
profile
.
save
()
UserPreference
.
set_preference
(
user
,
LANGUAGE_KEY
,
get_language
())
UserPreference
.
set_preference
(
user
,
LANGUAGE_KEY
,
get_language
())
# add this account creation to password history
# add this account creation to password history
...
@@ -179,7 +183,7 @@ class UsersDetail(APIView):
...
@@ -179,7 +183,7 @@ class UsersDetail(APIView):
response_data
=
{}
response_data
=
{}
base_uri
=
_generate_base_uri
(
request
)
base_uri
=
_generate_base_uri
(
request
)
try
:
try
:
existing_user
=
User
.
objects
.
get
(
id
=
user_id
,
is_active
=
True
)
existing_user
=
User
.
objects
.
get
(
id
=
user_id
)
_serialize_user
(
response_data
,
existing_user
)
_serialize_user
(
response_data
,
existing_user
)
response_data
[
'uri'
]
=
base_uri
response_data
[
'uri'
]
=
base_uri
response_data
[
'resources'
]
=
[]
response_data
[
'resources'
]
=
[]
...
@@ -191,36 +195,37 @@ class UsersDetail(APIView):
...
@@ -191,36 +195,37 @@ class UsersDetail(APIView):
except
ObjectDoesNotExist
:
except
ObjectDoesNotExist
:
return
Response
(
response_data
,
status
=
status
.
HTTP_404_NOT_FOUND
)
return
Response
(
response_data
,
status
=
status
.
HTTP_404_NOT_FOUND
)
def
delete
(
self
,
request
,
user_id
,
format
=
None
):
def
post
(
self
,
request
,
user_id
,
format
=
None
):
"""
"""
DELETE removes/inactivates/etc.
an existing user
POST provides the ability to update information about
an existing user
"""
"""
response_data
=
{}
response_data
=
{}
try
:
existing_user
=
User
.
objects
.
get
(
id
=
user_id
,
is_active
=
True
)
existing_user
.
is_active
=
False
existing_user
.
save
()
except
ObjectDoesNotExist
:
# It's ok if we don't find a match
pass
return
Response
(
response_data
,
status
=
status
.
HTTP_204_NO_CONTENT
)
def
post
(
self
,
request
,
user_id
,
format
=
None
):
response_data
=
{}
base_uri
=
_generate_base_uri
(
request
)
base_uri
=
_generate_base_uri
(
request
)
response_data
[
'uri'
]
=
_generate_base_uri
(
request
)
# Add some rate limiting here by re-using the RateLimitMixin as a helper class
# Add some rate limiting here by re-using the RateLimitMixin as a helper class
limiter
=
BadRequestRateLimiter
()
limiter
=
BadRequestRateLimiter
()
if
limiter
.
is_rate_limit_exceeded
(
request
):
if
limiter
.
is_rate_limit_exceeded
(
request
):
AUDIT_LOG
.
warning
(
"API::Rate limit exceeded in password_reset"
)
AUDIT_LOG
.
warning
(
"API::Rate limit exceeded in password_reset"
)
response_data
[
'message'
]
=
_
(
'Rate limit exceeded in password_reset.'
)
response_data
[
'message'
]
=
_
(
'Rate limit exceeded in password_reset.'
)
status_code
=
status
.
HTTP_403_FORBIDDEN
return
Response
(
response_data
,
status
=
status
.
HTTP_403_FORBIDDEN
)
return
Response
(
response_data
,
status
=
status_code
)
try
:
try
:
existing_user
=
User
.
objects
.
get
(
id
=
user_id
)
existing_user
=
User
.
objects
.
get
(
id
=
user_id
)
old_password_hash
=
existing_user
.
password
except
ObjectDoesNotExist
:
_serialize_user
(
response_data
,
existing_user
)
limiter
.
tick_bad_request_counter
(
request
)
password
=
request
.
DATA
[
'password'
]
existing_user
=
None
if
existing_user
:
if
existing_user
:
is_active
=
request
.
DATA
.
get
(
'is_active'
,
None
)
if
is_active
is
not
None
:
existing_user
.
is_active
=
is_active
response_data
[
'is_active'
]
=
existing_user
.
is_active
existing_user
.
save
()
password
=
request
.
DATA
.
get
(
'password'
)
if
password
:
old_password_hash
=
existing_user
.
password
_serialize_user
(
response_data
,
existing_user
)
password
=
request
.
DATA
[
'password'
]
if
settings
.
FEATURES
.
get
(
'ENFORCE_PASSWORD_POLICY'
,
False
):
if
settings
.
FEATURES
.
get
(
'ENFORCE_PASSWORD_POLICY'
,
False
):
try
:
try
:
validate_password_length
(
password
)
validate_password_length
(
password
)
...
@@ -270,17 +275,12 @@ class UsersDetail(APIView):
...
@@ -270,17 +275,12 @@ class UsersDetail(APIView):
password_history_entry
=
PasswordHistory
()
password_history_entry
=
PasswordHistory
()
password_history_entry
.
create
(
existing_user
)
password_history_entry
.
create
(
existing_user
)
status_code
=
status
.
HTTP_201_CREATED
status_code
=
status
.
HTTP_200_OK
response_data
[
'uri'
]
=
base_uri
response_data
[
'message'
]
=
'Password Reset Successful'
else
:
else
:
status_code
=
status
.
HTTP_404_NOT_FOUND
status_code
=
status
.
HTTP_404_NOT_FOUND
response_data
[
'message'
]
=
'User not exist'
response_data
[
'message'
]
=
'User not exist'
except
ObjectDoesNotExist
:
limiter
.
tick_bad_request_counter
(
request
)
return
Response
(
response_data
,
status
=
status
.
HTTP_404_NOT_FOUND
)
return
Response
(
response_data
,
status
=
status_code
)
return
Response
(
response_data
,
status
=
status_code
)
...
@@ -505,4 +505,4 @@ class UsersCoursesDetail(APIView):
...
@@ -505,4 +505,4 @@ class UsersCoursesDetail(APIView):
user
=
None
user
=
None
if
user
:
if
user
:
CourseEnrollment
.
unenroll
(
user
,
course_id
)
CourseEnrollment
.
unenroll
(
user
,
course_id
)
return
Response
({},
status
=
status
.
HTTP_204_NO_CONTENT
)
return
Response
({},
status
=
status
.
HTTP_204_NO_CONTENT
)
\ No newline at end of file
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