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
7fa7641c
Commit
7fa7641c
authored
Dec 02, 2013
by
Don Mitchell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1799 from edx/dhm/bug-1003
Improve auth handling of Locators
parents
45d373c2
9dc68b03
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
247 additions
and
94 deletions
+247
-94
cms/djangoapps/auth/authz.py
+87
-43
cms/djangoapps/contentstore/tests/test_permissions.py
+128
-0
cms/djangoapps/contentstore/tests/test_users.py
+2
-14
cms/djangoapps/contentstore/views/course.py
+2
-2
cms/djangoapps/contentstore/views/user.py
+28
-35
No files found.
cms/djangoapps/auth/authz.py
View file @
7fa7641c
"""
Studio authorization functions primarily for course creators, instructors, and staff
"""
#=======================================================================================================================
#=======================================================================================================================
#
#
# This code is somewhat duplicative of access.py in the LMS. We will unify the code as a separate story
# This code is somewhat duplicative of access.py in the LMS. We will unify the code as a separate story
...
@@ -11,7 +14,8 @@ from django.conf import settings
...
@@ -11,7 +14,8 @@ from django.conf import settings
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.locator
import
CourseLocator
,
Locator
from
xmodule.modulestore.locator
import
CourseLocator
,
Locator
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore.exceptions
import
InvalidLocationError
from
xmodule.modulestore.exceptions
import
InvalidLocationError
,
ItemNotFoundError
import
itertools
# define a couple of simple roles, we just need ADMIN and EDITOR now for our purposes
# define a couple of simple roles, we just need ADMIN and EDITOR now for our purposes
...
@@ -26,7 +30,11 @@ COURSE_CREATOR_GROUP_NAME = "course_creator_group"
...
@@ -26,7 +30,11 @@ COURSE_CREATOR_GROUP_NAME = "course_creator_group"
# of those two variables
# of those two variables
def
get_course_groupname_for_role
(
location
,
role
):
def
get_all_course_role_groupnames
(
location
,
role
,
use_filter
=
True
):
'''
Get all of the possible groupnames for this role location pair. If use_filter==True,
only return the ones defined in the groups collection.
'''
location
=
Locator
.
to_locator_or_location
(
location
)
location
=
Locator
.
to_locator_or_location
(
location
)
# hack: check for existence of a group name in the legacy LMS format <role>_<course>
# hack: check for existence of a group name in the legacy LMS format <role>_<course>
...
@@ -38,22 +46,46 @@ def get_course_groupname_for_role(location, role):
...
@@ -38,22 +46,46 @@ def get_course_groupname_for_role(location, role):
except
InvalidLocationError
:
# will occur on old locations where location is not of category course
except
InvalidLocationError
:
# will occur on old locations where location is not of category course
pass
pass
if
isinstance
(
location
,
Location
):
if
isinstance
(
location
,
Location
):
# least preferred role_course format
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course
))
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course
))
try
:
locator
=
loc_mapper
()
.
translate_location
(
location
.
course_id
,
location
,
False
,
False
)
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
locator
.
course_id
))
except
(
InvalidLocationError
,
ItemNotFoundError
):
pass
elif
isinstance
(
location
,
CourseLocator
):
elif
isinstance
(
location
,
CourseLocator
):
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
,
get_course
=
True
)
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
,
get_course
=
True
)
if
old_location
:
if
old_location
:
# the slashified version of the course_id (myu/mycourse/myrun)
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
old_location
.
course_id
))
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
old_location
.
course_id
))
# add the least desirable but sometimes occurring format.
for
groupname
in
groupnames
:
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
old_location
.
course
))
if
Group
.
objects
.
filter
(
name
=
groupname
)
.
exists
():
# filter to the ones which exist
return
groupname
default
=
groupnames
[
0
]
return
groupnames
[
0
]
if
use_filter
:
groupnames
=
[
group
for
group
in
groupnames
if
Group
.
objects
.
filter
(
name
=
group
)
.
exists
()]
return
groupnames
,
default
def
get_users_in_course_group_by_role
(
location
,
role
):
def
get_course_groupname_for_role
(
location
,
role
):
groupname
=
get_course_groupname_for_role
(
location
,
role
)
'''
(
group
,
_created
)
=
Group
.
objects
.
get_or_create
(
name
=
groupname
)
Get the preferred used groupname for this role, location combo.
return
group
.
user_set
.
all
()
Preference order:
* role_course_id (e.g., staff_myu.mycourse.myrun)
* role_old_course_id (e.g., staff_myu/mycourse/myrun)
* role_old_course (e.g., staff_mycourse)
'''
groupnames
,
default
=
get_all_course_role_groupnames
(
location
,
role
)
return
groupnames
[
0
]
if
groupnames
else
default
def
get_course_role_users
(
course_locator
,
role
):
'''
Get all of the users with the given role in the given course.
'''
groupnames
,
_
=
get_all_course_role_groupnames
(
course_locator
,
role
)
groups
=
[
Group
.
objects
.
get
(
name
=
groupname
)
for
groupname
in
groupnames
]
return
list
(
itertools
.
chain
.
from_iterable
(
group
.
user_set
.
all
()
for
group
in
groups
))
def
create_all_course_groups
(
creator
,
location
):
def
create_all_course_groups
(
creator
,
location
):
...
@@ -65,11 +97,11 @@ def create_all_course_groups(creator, location):
...
@@ -65,11 +97,11 @@ def create_all_course_groups(creator, location):
def
create_new_course_group
(
creator
,
location
,
role
):
def
create_new_course_group
(
creator
,
location
,
role
):
groupname
=
get_course_groupname_for_role
(
location
,
role
)
'''
(
group
,
created
)
=
Group
.
objects
.
get_or_create
(
name
=
groupname
)
Create the new course group always using the preferred name even if another form already exists.
if
created
:
'''
group
.
save
(
)
groupnames
,
__
=
get_all_course_role_groupnames
(
location
,
role
,
use_filter
=
False
)
group
,
__
=
Group
.
objects
.
get_or_create
(
name
=
groupnames
[
0
])
creator
.
groups
.
add
(
group
)
creator
.
groups
.
add
(
group
)
creator
.
save
()
creator
.
save
()
...
@@ -82,15 +114,13 @@ def _delete_course_group(location):
...
@@ -82,15 +114,13 @@ def _delete_course_group(location):
asserted permissions
asserted permissions
"""
"""
# remove all memberships
# remove all memberships
instructors
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
location
,
INSTRUCTOR_ROLE_NAME
))
for
role
in
[
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
]:
for
user
in
instructors
.
user_set
.
all
():
groupnames
,
_
=
get_all_course_role_groupnames
(
location
,
role
)
user
.
groups
.
remove
(
instructors
)
for
groupname
in
groupnames
:
user
.
save
()
group
=
Group
.
objects
.
get
(
name
=
groupname
)
for
user
in
group
.
user_set
.
all
():
staff
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
location
,
STAFF_ROLE_NAME
))
user
.
groups
.
remove
(
group
)
for
user
in
staff
.
user_set
.
all
():
user
.
save
()
user
.
groups
.
remove
(
staff
)
user
.
save
()
def
_copy_course_group
(
source
,
dest
):
def
_copy_course_group
(
source
,
dest
):
...
@@ -98,25 +128,25 @@ def _copy_course_group(source, dest):
...
@@ -98,25 +128,25 @@ def _copy_course_group(source, dest):
This is to be called only by either a command line code path or through an app which has already
This is to be called only by either a command line code path or through an app which has already
asserted permissions to do this action
asserted permissions to do this action
"""
"""
instructors
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
source
,
INSTRUCTOR_ROLE_NAME
))
for
role
in
[
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
]:
new_instructors_group
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
dest
,
INSTRUCTOR_ROLE_NAME
))
groupnames
,
_
=
get_all_course_role_groupnames
(
source
,
role
)
for
user
in
instructors
.
user_set
.
all
():
for
groupname
in
groupnames
:
user
.
groups
.
add
(
new_instructors_group
)
group
=
Group
.
objects
.
get
(
name
=
groupname
)
user
.
save
()
new_group
,
_
=
Group
.
objects
.
get_or_create
(
name
=
get_course_groupname_for_role
(
dest
,
INSTRUCTOR_ROLE_NAME
))
for
user
in
group
.
user_set
.
all
():
staff
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
source
,
STAFF_ROLE_NAME
))
user
.
groups
.
add
(
new_group
)
new_staff_group
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
dest
,
STAFF_ROLE_NAME
))
user
.
save
()
for
user
in
staff
.
user_set
.
all
():
user
.
groups
.
add
(
new_staff_group
)
user
.
save
()
def
add_user_to_course_group
(
caller
,
user
,
location
,
role
):
def
add_user_to_course_group
(
caller
,
user
,
location
,
role
):
"""
If caller is authorized, add the given user to the given course's role
"""
# only admins can add/remove other users
# only admins can add/remove other users
if
not
is_user_in_course_group_role
(
caller
,
location
,
INSTRUCTOR_ROLE_NAME
):
if
not
is_user_in_course_group_role
(
caller
,
location
,
INSTRUCTOR_ROLE_NAME
):
raise
PermissionDenied
raise
PermissionDenied
group
=
Group
.
objects
.
get
(
name
=
get_course_groupname_for_role
(
location
,
role
))
group
,
_
=
Group
.
objects
.
get_or_create
(
name
=
get_course_groupname_for_role
(
location
,
role
))
return
_add_user_to_group
(
user
,
group
)
return
_add_user_to_group
(
user
,
group
)
...
@@ -132,9 +162,7 @@ def add_user_to_creator_group(caller, user):
...
@@ -132,9 +162,7 @@ def add_user_to_creator_group(caller, user):
if
not
caller
.
is_active
or
not
caller
.
is_authenticated
or
not
caller
.
is_staff
:
if
not
caller
.
is_active
or
not
caller
.
is_authenticated
or
not
caller
.
is_staff
:
raise
PermissionDenied
raise
PermissionDenied
(
group
,
created
)
=
Group
.
objects
.
get_or_create
(
name
=
COURSE_CREATOR_GROUP_NAME
)
(
group
,
_
)
=
Group
.
objects
.
get_or_create
(
name
=
COURSE_CREATOR_GROUP_NAME
)
if
created
:
group
.
save
()
return
_add_user_to_group
(
user
,
group
)
return
_add_user_to_group
(
user
,
group
)
...
@@ -152,6 +180,9 @@ def _add_user_to_group(user, group):
...
@@ -152,6 +180,9 @@ def _add_user_to_group(user, group):
def
get_user_by_email
(
email
):
def
get_user_by_email
(
email
):
"""
Get the user whose email is the arg. Return None if no such user exists.
"""
user
=
None
user
=
None
# try to look up user, return None if not found
# try to look up user, return None if not found
try
:
try
:
...
@@ -163,13 +194,21 @@ def get_user_by_email(email):
...
@@ -163,13 +194,21 @@ def get_user_by_email(email):
def
remove_user_from_course_group
(
caller
,
user
,
location
,
role
):
def
remove_user_from_course_group
(
caller
,
user
,
location
,
role
):
"""
If caller is authorized, remove the given course x role authorization for user
"""
# only admins can add/remove other users
# only admins can add/remove other users
if
not
is_user_in_course_group_role
(
caller
,
location
,
INSTRUCTOR_ROLE_NAME
):
if
not
is_user_in_course_group_role
(
caller
,
location
,
INSTRUCTOR_ROLE_NAME
):
raise
PermissionDenied
raise
PermissionDenied
# see if the user is actually in that role, if not then we don't have to do anything
# see if the user is actually in that role, if not then we don't have to do anything
if
is_user_in_course_group_role
(
user
,
location
,
role
):
groupnames
,
_
=
get_all_course_role_groupnames
(
location
,
role
)
_remove_user_from_group
(
user
,
get_course_groupname_for_role
(
location
,
role
))
for
groupname
in
groupnames
:
groups
=
user
.
groups
.
filter
(
name
=
groupname
)
if
groups
:
# will only be one with that name
user
.
groups
.
remove
(
groups
[
0
])
user
.
save
()
def
remove_user_from_creator_group
(
caller
,
user
):
def
remove_user_from_creator_group
(
caller
,
user
):
...
@@ -195,11 +234,16 @@ def _remove_user_from_group(user, group_name):
...
@@ -195,11 +234,16 @@ def _remove_user_from_group(user, group_name):
def
is_user_in_course_group_role
(
user
,
location
,
role
,
check_staff
=
True
):
def
is_user_in_course_group_role
(
user
,
location
,
role
,
check_staff
=
True
):
"""
Check whether the given user has the given role in this course. If check_staff
then give permission if the user is staff without doing a course-role query.
"""
if
user
.
is_active
and
user
.
is_authenticated
:
if
user
.
is_active
and
user
.
is_authenticated
:
# all "is_staff" flagged accounts belong to all groups
# all "is_staff" flagged accounts belong to all groups
if
check_staff
and
user
.
is_staff
:
if
check_staff
and
user
.
is_staff
:
return
True
return
True
return
user
.
groups
.
filter
(
name
=
get_course_groupname_for_role
(
location
,
role
))
.
exists
()
groupnames
,
_
=
get_all_course_role_groupnames
(
location
,
role
)
return
any
(
user
.
groups
.
filter
(
name
=
groupname
)
.
exists
()
for
groupname
in
groupnames
)
return
False
return
False
...
...
cms/djangoapps/contentstore/tests/test_permissions.py
0 → 100644
View file @
7fa7641c
"""
Test CRUD for authorization.
"""
from
django.test.utils
import
override_settings
from
django.contrib.auth.models
import
User
,
Group
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
contentstore.tests.modulestore_config
import
TEST_MODULESTORE
from
contentstore.tests.utils
import
AjaxEnabledTestClient
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore
import
Location
from
auth.authz
import
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
from
auth
import
authz
import
copy
from
contentstore.views.access
import
has_access
@override_settings
(
MODULESTORE
=
TEST_MODULESTORE
)
class
TestCourseAccess
(
ModuleStoreTestCase
):
"""
Course-based access (as opposed to access of a non-course xblock)
"""
def
setUp
(
self
):
"""
Create a staff user and log them in (creating the client).
Create a pool of users w/o granting them any permissions
"""
super
(
TestCourseAccess
,
self
)
.
setUp
()
uname
=
'testuser'
email
=
'test+courses@edx.org'
password
=
'foo'
# Create the use so we can log them in.
self
.
user
=
User
.
objects
.
create_user
(
uname
,
email
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self
.
user
.
is_active
=
True
# Staff has access to view all courses
self
.
user
.
is_staff
=
True
self
.
user
.
save
()
self
.
client
=
AjaxEnabledTestClient
()
self
.
client
.
login
(
username
=
uname
,
password
=
password
)
# create a course via the view handler which has a different strategy for permissions than the factory
self
.
course_location
=
Location
([
'i4x'
,
'myu'
,
'mydept.mycourse'
,
'course'
,
'myrun'
])
self
.
course_locator
=
loc_mapper
()
.
translate_location
(
self
.
course_location
.
course_id
,
self
.
course_location
,
False
,
True
)
self
.
client
.
ajax_post
(
self
.
course_locator
.
url_reverse
(
'course'
),
{
'org'
:
self
.
course_location
.
org
,
'number'
:
self
.
course_location
.
course
,
'display_name'
:
'My favorite course'
,
'run'
:
self
.
course_location
.
name
,
}
)
self
.
users
=
self
.
_create_users
()
def
_create_users
(
self
):
"""
Create 8 users and return them
"""
users
=
[]
for
i
in
range
(
8
):
username
=
"user{}"
.
format
(
i
)
email
=
"test+user{}@edx.org"
.
format
(
i
)
user
=
User
.
objects
.
create_user
(
username
,
email
,
'foo'
)
user
.
is_active
=
True
user
.
save
()
users
.
append
(
user
)
return
users
def
tearDown
(
self
):
"""
Reverse the setup
"""
self
.
client
.
logout
()
ModuleStoreTestCase
.
tearDown
(
self
)
def
test_get_all_users
(
self
):
"""
Test getting all authors for a course where their permissions run the gamut of allowed group
types.
"""
# first check the groupname for the course creator.
self
.
assertTrue
(
self
.
user
.
groups
.
filter
(
name
=
"{}_{}"
.
format
(
INSTRUCTOR_ROLE_NAME
,
self
.
course_locator
.
course_id
)
)
.
exists
(),
"Didn't add creator as instructor."
)
users
=
copy
.
copy
(
self
.
users
)
user_by_role
=
{}
# add the misc users to the course in different groups
for
role
in
[
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
]:
user_by_role
[
role
]
=
[]
groupnames
,
_
=
authz
.
get_all_course_role_groupnames
(
self
.
course_locator
,
role
)
for
groupname
in
groupnames
:
group
,
_
=
Group
.
objects
.
get_or_create
(
name
=
groupname
)
user
=
users
.
pop
()
user_by_role
[
role
]
.
append
(
user
)
user
.
groups
.
add
(
group
)
user
.
save
()
self
.
assertTrue
(
has_access
(
user
,
self
.
course_locator
),
"{} does not have access"
.
format
(
user
))
self
.
assertTrue
(
has_access
(
user
,
self
.
course_location
),
"{} does not have access"
.
format
(
user
))
response
=
self
.
client
.
get_html
(
self
.
course_locator
.
url_reverse
(
'course_team'
))
for
role
in
[
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
]:
for
user
in
user_by_role
[
role
]:
self
.
assertContains
(
response
,
user
.
email
)
# test copying course permissions
copy_course_location
=
Location
([
'i4x'
,
'copyu'
,
'copydept.mycourse'
,
'course'
,
'myrun'
])
copy_course_locator
=
loc_mapper
()
.
translate_location
(
copy_course_location
.
course_id
,
copy_course_location
,
False
,
True
)
# pylint: disable=protected-access
authz
.
_copy_course_group
(
self
.
course_locator
,
copy_course_locator
)
for
role
in
[
INSTRUCTOR_ROLE_NAME
,
STAFF_ROLE_NAME
]:
for
user
in
user_by_role
[
role
]:
self
.
assertTrue
(
has_access
(
user
,
copy_course_locator
),
"{} no copy access"
.
format
(
user
))
self
.
assertTrue
(
has_access
(
user
,
copy_course_location
),
"{} no copy access"
.
format
(
user
))
\ No newline at end of file
cms/djangoapps/contentstore/tests/test_users.py
View file @
7fa7641c
...
@@ -29,8 +29,8 @@ class UsersTestCase(CourseTestCase):
...
@@ -29,8 +29,8 @@ class UsersTestCase(CourseTestCase):
self
.
detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
self
.
ext_user
.
email
)
self
.
detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
self
.
ext_user
.
email
)
self
.
inactive_detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
self
.
inactive_user
.
email
)
self
.
inactive_detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
self
.
inactive_user
.
email
)
self
.
invalid_detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
"nonexistent@user.com"
)
self
.
invalid_detail_url
=
self
.
location
.
url_reverse
(
'course_team'
,
"nonexistent@user.com"
)
self
.
staff_groupname
=
get_course_groupname_for_role
(
self
.
course
.
location
,
"staff"
)
self
.
staff_groupname
=
get_course_groupname_for_role
(
self
.
course
_locator
,
"staff"
)
self
.
inst_groupname
=
get_course_groupname_for_role
(
self
.
course
.
location
,
"instructor"
)
self
.
inst_groupname
=
get_course_groupname_for_role
(
self
.
course
_locator
,
"instructor"
)
def
test_index
(
self
):
def
test_index
(
self
):
resp
=
self
.
client
.
get
(
self
.
index_url
,
HTTP_ACCEPT
=
'text/html'
)
resp
=
self
.
client
.
get
(
self
.
index_url
,
HTTP_ACCEPT
=
'text/html'
)
...
@@ -145,18 +145,6 @@ class UsersTestCase(CourseTestCase):
...
@@ -145,18 +145,6 @@ class UsersTestCase(CourseTestCase):
self
.
assertIn
(
"error"
,
result
)
self
.
assertIn
(
"error"
,
result
)
self
.
assert_not_enrolled
()
self
.
assert_not_enrolled
()
def
test_detail_post_bad_json
(
self
):
resp
=
self
.
client
.
post
(
self
.
detail_url
,
data
=
"{foo}"
,
content_type
=
"application/json"
,
HTTP_ACCEPT
=
"application/json"
,
)
self
.
assertEqual
(
resp
.
status_code
,
400
)
result
=
json
.
loads
(
resp
.
content
)
self
.
assertIn
(
"error"
,
result
)
self
.
assert_not_enrolled
()
def
test_detail_post_no_json
(
self
):
def
test_detail_post_no_json
(
self
):
resp
=
self
.
client
.
post
(
resp
=
self
.
client
.
post
(
self
.
detail_url
,
self
.
detail_url
,
...
...
cms/djangoapps/contentstore/views/course.py
View file @
7fa7641c
...
@@ -292,7 +292,8 @@ def create_new_course(request):
...
@@ -292,7 +292,8 @@ def create_new_course(request):
initialize_course_tabs
(
new_course
)
initialize_course_tabs
(
new_course
)
create_all_course_groups
(
request
.
user
,
new_course
.
location
)
new_location
=
loc_mapper
()
.
translate_location
(
new_course
.
location
.
course_id
,
new_course
.
location
,
False
,
True
)
create_all_course_groups
(
request
.
user
,
new_location
)
# seed the forums
# seed the forums
seed_permissions_roles
(
new_course
.
location
.
course_id
)
seed_permissions_roles
(
new_course
.
location
.
course_id
)
...
@@ -301,7 +302,6 @@ def create_new_course(request):
...
@@ -301,7 +302,6 @@ def create_new_course(request):
# work.
# work.
CourseEnrollment
.
enroll
(
request
.
user
,
new_course
.
location
.
course_id
)
CourseEnrollment
.
enroll
(
request
.
user
,
new_course
.
location
.
course_id
)
new_location
=
loc_mapper
()
.
translate_location
(
new_course
.
location
.
course_id
,
new_course
.
location
,
False
,
True
)
return
JsonResponse
({
'url'
:
new_location
.
url_reverse
(
"course/"
,
""
)})
return
JsonResponse
({
'url'
:
new_location
.
url_reverse
(
"course/"
,
""
)})
...
...
cms/djangoapps/contentstore/views/user.py
View file @
7fa7641c
import
json
import
json
from
django.conf
import
settings
from
django.core.exceptions
import
PermissionDenied
from
django.core.exceptions
import
PermissionDenied
from
django.contrib.auth.models
import
User
,
Group
from
django.contrib.auth.models
import
User
,
Group
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.auth.decorators
import
login_required
...
@@ -10,9 +9,11 @@ from django_future.csrf import ensure_csrf_cookie
...
@@ -10,9 +9,11 @@ from django_future.csrf import ensure_csrf_cookie
from
mitxmako.shortcuts
import
render_to_response
from
mitxmako.shortcuts
import
render_to_response
from
xmodule.modulestore.django
import
modulestore
,
loc_mapper
from
xmodule.modulestore.django
import
modulestore
,
loc_mapper
from
util.json_request
import
JsonResponse
from
util.json_request
import
JsonResponse
,
expect_json
from
auth.authz
import
(
from
auth.authz
import
(
STAFF_ROLE_NAME
,
INSTRUCTOR_ROLE_NAME
,
get_course_groupname_for_role
)
STAFF_ROLE_NAME
,
INSTRUCTOR_ROLE_NAME
,
get_course_groupname_for_role
,
get_course_role_users
)
from
course_creators.views
import
user_requested_access
from
course_creators.views
import
user_requested_access
from
.access
import
has_access
from
.access
import
has_access
...
@@ -35,6 +36,7 @@ def request_course_creator(request):
...
@@ -35,6 +36,7 @@ def request_course_creator(request):
return
JsonResponse
({
"Status"
:
"OK"
})
return
JsonResponse
({
"Status"
:
"OK"
})
# pylint: disable=unused-argument
@login_required
@login_required
@ensure_csrf_cookie
@ensure_csrf_cookie
@require_http_methods
((
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
))
@require_http_methods
((
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
))
...
@@ -62,38 +64,39 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_
...
@@ -62,38 +64,39 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_
return
HttpResponseNotFound
()
return
HttpResponseNotFound
()
def
_manage_users
(
request
,
locat
ion
):
def
_manage_users
(
request
,
locat
or
):
"""
"""
This view will return all CMS users who are editors for the specified course
This view will return all CMS users who are editors for the specified course
"""
"""
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
locat
ion
)
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
locat
or
)
# check that logged in user has permissions to this item
# check that logged in user has permissions to this item
if
not
has_access
(
request
.
user
,
locat
ion
,
role
=
INSTRUCTOR_ROLE_NAME
)
and
not
has_access
(
request
.
user
,
location
,
role
=
STAFF_ROLE_NAME
):
if
not
has_access
(
request
.
user
,
locat
or
):
raise
PermissionDenied
()
raise
PermissionDenied
()
course_module
=
modulestore
()
.
get_item
(
old_location
)
course_module
=
modulestore
()
.
get_item
(
old_location
)
instructors
=
get_course_role_users
(
locator
,
INSTRUCTOR_ROLE_NAME
)
staff_groupname
=
get_course_groupname_for_role
(
location
,
"staff"
)
# the page only lists staff and assumes they're a superset of instructors. Do a union to ensure.
staff_group
,
__
=
Group
.
objects
.
get_or_create
(
name
=
staff_groupname
)
staff
=
set
(
get_course_role_users
(
locator
,
STAFF_ROLE_NAME
))
.
union
(
instructors
)
inst_groupname
=
get_course_groupname_for_role
(
location
,
"instructor"
)
inst_group
,
__
=
Group
.
objects
.
get_or_create
(
name
=
inst_groupname
)
return
render_to_response
(
'manage_users.html'
,
{
return
render_to_response
(
'manage_users.html'
,
{
'context_course'
:
course_module
,
'context_course'
:
course_module
,
'staff'
:
staff
_group
.
user_set
.
all
()
,
'staff'
:
staff
,
'instructors'
:
inst
_group
.
user_set
.
all
()
,
'instructors'
:
inst
ructors
,
'allow_actions'
:
has_access
(
request
.
user
,
locat
ion
,
role
=
INSTRUCTOR_ROLE_NAME
),
'allow_actions'
:
has_access
(
request
.
user
,
locat
or
,
role
=
INSTRUCTOR_ROLE_NAME
),
})
})
def
_course_team_user
(
request
,
location
,
email
):
@expect_json
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
)
def
_course_team_user
(
request
,
locator
,
email
):
"""
Handle the add, remove, promote, demote requests ensuring the requester has authority
"""
# check that logged in user has permissions to this item
# check that logged in user has permissions to this item
if
has_access
(
request
.
user
,
locat
ion
,
role
=
INSTRUCTOR_ROLE_NAME
):
if
has_access
(
request
.
user
,
locat
or
,
role
=
INSTRUCTOR_ROLE_NAME
):
# instructors have full permissions
# instructors have full permissions
pass
pass
elif
has_access
(
request
.
user
,
locat
ion
,
role
=
STAFF_ROLE_NAME
)
and
email
==
request
.
user
.
email
:
elif
has_access
(
request
.
user
,
locat
or
,
role
=
STAFF_ROLE_NAME
)
and
email
==
request
.
user
.
email
:
# staff can only affect themselves
# staff can only affect themselves
pass
pass
else
:
else
:
...
@@ -123,7 +126,7 @@ def _course_team_user(request, location, email):
...
@@ -123,7 +126,7 @@ def _course_team_user(request, location, email):
# what's the highest role that this user has?
# what's the highest role that this user has?
groupnames
=
set
(
g
.
name
for
g
in
user
.
groups
.
all
())
groupnames
=
set
(
g
.
name
for
g
in
user
.
groups
.
all
())
for
role
in
roles
:
for
role
in
roles
:
role_groupname
=
get_course_groupname_for_role
(
old_location
,
role
)
role_groupname
=
get_course_groupname_for_role
(
locator
,
role
)
if
role_groupname
in
groupnames
:
if
role_groupname
in
groupnames
:
msg
[
"role"
]
=
role
msg
[
"role"
]
=
role
break
break
...
@@ -139,7 +142,7 @@ def _course_team_user(request, location, email):
...
@@ -139,7 +142,7 @@ def _course_team_user(request, location, email):
# make sure that the role groups exist
# make sure that the role groups exist
groups
=
{}
groups
=
{}
for
role
in
roles
:
for
role
in
roles
:
groupname
=
get_course_groupname_for_role
(
old_location
,
role
)
groupname
=
get_course_groupname_for_role
(
locator
,
role
)
group
,
__
=
Group
.
objects
.
get_or_create
(
name
=
groupname
)
group
,
__
=
Group
.
objects
.
get_or_create
(
name
=
groupname
)
groups
[
role
]
=
group
groups
[
role
]
=
group
...
@@ -162,22 +165,13 @@ def _course_team_user(request, location, email):
...
@@ -162,22 +165,13 @@ def _course_team_user(request, location, email):
return
JsonResponse
()
return
JsonResponse
()
# all other operations require the requesting user to specify a role
# all other operations require the requesting user to specify a role
if
request
.
META
.
get
(
"CONTENT_TYPE"
,
""
)
.
startswith
(
"application/json"
)
and
request
.
body
:
role
=
request
.
json
.
get
(
"role"
,
request
.
POST
.
get
(
"role"
))
try
:
if
role
is
None
:
payload
=
json
.
loads
(
request
.
body
)
return
JsonResponse
({
"error"
:
_
(
"`role` is required"
)},
400
)
except
:
return
JsonResponse
({
"error"
:
_
(
"malformed JSON"
)},
400
)
try
:
role
=
payload
[
"role"
]
except
KeyError
:
return
JsonResponse
({
"error"
:
_
(
"`role` is required"
)},
400
)
else
:
if
not
"role"
in
request
.
POST
:
return
JsonResponse
({
"error"
:
_
(
"`role` is required"
)},
400
)
role
=
request
.
POST
[
"role"
]
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
locator
)
if
role
==
"instructor"
:
if
role
==
"instructor"
:
if
not
has_access
(
request
.
user
,
locat
ion
,
role
=
INSTRUCTOR_ROLE_NAME
):
if
not
has_access
(
request
.
user
,
locat
or
,
role
=
INSTRUCTOR_ROLE_NAME
):
msg
=
{
msg
=
{
"error"
:
_
(
"Only instructors may create other instructors"
)
"error"
:
_
(
"Only instructors may create other instructors"
)
}
}
...
@@ -203,4 +197,3 @@ def _course_team_user(request, location, email):
...
@@ -203,4 +197,3 @@ def _course_team_user(request, location, email):
CourseEnrollment
.
enroll
(
user
,
old_location
.
course_id
)
CourseEnrollment
.
enroll
(
user
,
old_location
.
course_id
)
return
JsonResponse
()
return
JsonResponse
()
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