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
d78d52e1
Commit
d78d52e1
authored
Apr 25, 2017
by
noraiz-anwar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add masquerading feature for preview mode
parent
b3a9689d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
67 additions
and
100 deletions
+67
-100
lms/djangoapps/courseware/access.py
+31
-55
lms/djangoapps/courseware/tests/test_access.py
+36
-45
No files found.
lms/djangoapps/courseware/access.py
View file @
d78d52e1
...
@@ -136,8 +136,9 @@ def has_access(user, action, obj, course_key=None):
...
@@ -136,8 +136,9 @@ def has_access(user, action, obj, course_key=None):
if
not
user
:
if
not
user
:
user
=
AnonymousUser
()
user
=
AnonymousUser
()
if
in_preview_mode
():
# Preview mode is only accessible by staff.
if
not
bool
(
has_staff_access_to_preview_mode
(
user
=
user
,
obj
=
obj
,
course_key
=
course_key
)):
if
in_preview_mode
()
and
course_key
:
if
not
has_staff_access_to_preview_mode
(
user
,
course_key
):
return
ACCESS_DENIED
return
ACCESS_DENIED
# delegate the work to type-specific functions.
# delegate the work to type-specific functions.
...
@@ -173,51 +174,14 @@ def has_access(user, action, obj, course_key=None):
...
@@ -173,51 +174,14 @@ def has_access(user, action, obj, course_key=None):
.
format
(
type
(
obj
)))
.
format
(
type
(
obj
)))
# ================ Implementation helpers ================================
def
has_staff_access_to_preview_mode
(
user
,
course_key
):
def
has_staff_access_to_preview_mode
(
user
,
obj
,
course_key
=
None
):
"""
"""
Returns whether user has staff access to specified modules or not.
Checks if given user can access course in preview mode.
A user can access a course in preview mode only if User has staff access to course.
Arguments:
user: a Django user object.
obj: The object to check access for.
course_key: A course_key specifying which course this access is for.
Returns an AccessResponse object.
"""
"""
if
course_key
is
None
:
has_admin_access_to_course
=
any
(
administrative_accesses_to_course_for_user
(
user
,
course_key
))
if
isinstance
(
obj
,
CourseDescriptor
)
or
isinstance
(
obj
,
CourseOverview
):
course_key
=
obj
.
id
elif
isinstance
(
obj
,
ErrorDescriptor
):
course_key
=
obj
.
location
.
course_key
elif
isinstance
(
obj
,
XModule
):
course_key
=
obj
.
descriptor
.
course_key
elif
isinstance
(
obj
,
XBlock
):
course_key
=
obj
.
location
.
course_key
elif
isinstance
(
obj
,
CCXLocator
):
return
has_admin_access_to_course
or
is_masquerading_as_student
(
user
,
course_key
)
course_key
=
obj
.
to_course_locator
()
elif
isinstance
(
obj
,
CourseKey
):
course_key
=
obj
elif
isinstance
(
obj
,
UsageKey
):
course_key
=
obj
.
course_key
if
course_key
is
None
:
if
GlobalStaff
()
.
has_user
(
user
):
return
ACCESS_GRANTED
else
:
return
ACCESS_DENIED
return
_has_access_to_course
(
user
,
'staff'
,
course_key
=
course_key
)
def
_can_access_descriptor_with_start_date
(
user
,
descriptor
,
course_key
):
# pylint: disable=invalid-name
def
_can_access_descriptor_with_start_date
(
user
,
descriptor
,
course_key
):
# pylint: disable=invalid-name
...
@@ -733,10 +697,12 @@ def _has_access_to_course(user, access_level, course_key):
...
@@ -733,10 +697,12 @@ def _has_access_to_course(user, access_level, course_key):
debug
(
"Deny: no user or anon user"
)
debug
(
"Deny: no user or anon user"
)
return
ACCESS_DENIED
return
ACCESS_DENIED
if
not
in_preview_mode
()
and
is_masquerading_as_student
(
user
,
course_key
):
if
is_masquerading_as_student
(
user
,
course_key
):
return
ACCESS_DENIED
return
ACCESS_DENIED
if
GlobalStaff
()
.
has_user
(
user
):
global_staff
,
staff_access
,
instructor_access
=
administrative_accesses_to_course_for_user
(
user
,
course_key
)
if
global_staff
:
debug
(
"Allow: user.is_staff"
)
debug
(
"Allow: user.is_staff"
)
return
ACCESS_GRANTED
return
ACCESS_GRANTED
...
@@ -745,19 +711,10 @@ def _has_access_to_course(user, access_level, course_key):
...
@@ -745,19 +711,10 @@ def _has_access_to_course(user, access_level, course_key):
debug
(
"Deny: unknown access level"
)
debug
(
"Deny: unknown access level"
)
return
ACCESS_DENIED
return
ACCESS_DENIED
staff_access
=
(
CourseStaffRole
(
course_key
)
.
has_user
(
user
)
or
OrgStaffRole
(
course_key
.
org
)
.
has_user
(
user
)
)
if
staff_access
and
access_level
==
'staff'
:
if
staff_access
and
access_level
==
'staff'
:
debug
(
"Allow: user has course staff access"
)
debug
(
"Allow: user has course staff access"
)
return
ACCESS_GRANTED
return
ACCESS_GRANTED
instructor_access
=
(
CourseInstructorRole
(
course_key
)
.
has_user
(
user
)
or
OrgInstructorRole
(
course_key
.
org
)
.
has_user
(
user
)
)
if
instructor_access
and
access_level
in
(
'staff'
,
'instructor'
):
if
instructor_access
and
access_level
in
(
'staff'
,
'instructor'
):
debug
(
"Allow: user has course instructor access"
)
debug
(
"Allow: user has course instructor access"
)
return
ACCESS_GRANTED
return
ACCESS_GRANTED
...
@@ -766,6 +723,25 @@ def _has_access_to_course(user, access_level, course_key):
...
@@ -766,6 +723,25 @@ def _has_access_to_course(user, access_level, course_key):
return
ACCESS_DENIED
return
ACCESS_DENIED
def
administrative_accesses_to_course_for_user
(
user
,
course_key
):
"""
Returns types of access a user have for given course.
"""
global_staff
=
GlobalStaff
()
.
has_user
(
user
)
staff_access
=
(
CourseStaffRole
(
course_key
)
.
has_user
(
user
)
or
OrgStaffRole
(
course_key
.
org
)
.
has_user
(
user
)
)
instructor_access
=
(
CourseInstructorRole
(
course_key
)
.
has_user
(
user
)
or
OrgInstructorRole
(
course_key
.
org
)
.
has_user
(
user
)
)
return
global_staff
,
staff_access
,
instructor_access
def
_has_instructor_access_to_descriptor
(
user
,
descriptor
,
course_key
):
# pylint: disable=invalid-name
def
_has_instructor_access_to_descriptor
(
user
,
descriptor
,
course_key
):
# pylint: disable=invalid-name
"""Helper method that checks whether the user has staff access to
"""Helper method that checks whether the user has staff access to
the course of the location.
the course of the location.
...
...
lms/djangoapps/courseware/tests/test_access.py
View file @
d78d52e1
...
@@ -199,44 +199,41 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -199,44 +199,41 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
def
test_has_staff_access_to_preview_mode
(
self
):
def
test_has_staff_access_to_preview_mode
(
self
):
"""
"""
Test
s users have right access to content in preview mode
.
Test
that preview mode is only accessible by staff users
.
"""
"""
course_key
=
self
.
course
.
id
course_key
=
self
.
course
.
id
usage_key
=
self
.
course
.
scope_ids
.
usage_id
CourseEnrollmentFactory
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
)
chapter
=
ItemFactory
.
create
(
category
=
"chapter"
,
parent_location
=
self
.
course
.
location
)
overview
=
CourseOverview
.
get_from_id
(
course_key
)
test_system
=
get_test_system
()
ccx
=
CcxFactory
(
course_id
=
course_key
)
for
user
in
[
self
.
global_staff
,
self
.
course_staff
,
self
.
course_instructor
]:
ccx_locator
=
CCXLocator
.
from_course_locator
(
course_key
,
ccx
.
id
)
self
.
assertTrue
(
access
.
has_staff_access_to_preview_mode
(
user
,
course_key
)
)
error_descriptor
=
ErrorDescriptor
.
from_xml
(
self
.
assertFalse
(
access
.
has_staff_access_to_preview_mode
(
self
.
student
,
course_key
))
u"<problem>ABC
\N{SNOWMAN}
</problem>"
,
test_system
,
CourseLocationManager
(
course_key
),
"error msg"
)
# Enroll student to the course
CourseEnrollmentFactory
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
)
modules
=
[
# we don't want to restrict a staff user, masquerading as student,
self
.
course
,
# to access preview mode.
overview
,
chapter
,
ccx_locator
,
error_descriptor
,
course_key
,
usage_key
,
]
# Course key is not None
self
.
assertTrue
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
global_staff
,
obj
=
self
.
course
,
course_key
=
course_key
))
)
for
user
in
[
self
.
global_staff
,
self
.
course_staff
,
self
.
course_instructor
]:
# Note that self.student now have access to preview mode,
for
obj
in
modules
:
# `is_masquerading_as_student == True` means user is staff and is
self
.
assertTrue
(
bool
(
access
.
has_staff_access_to_preview_mode
(
user
,
obj
=
obj
)))
# masquerading as a student.
self
.
assertFalse
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
student
,
obj
=
obj
)))
with
patch
(
'courseware.access.is_masquerading_as_student'
)
as
mock_masquerade
:
mock_masquerade
.
return_value
=
True
for
user
in
[
self
.
global_staff
,
self
.
course_staff
,
self
.
course_instructor
,
self
.
student
]:
self
.
assertTrue
(
access
.
has_staff_access_to_preview_mode
(
user
,
course_key
))
def
test_administrative_accesses_to_course_for_user
(
self
):
"""
Test types of admin accesses to a course
"""
course_key
=
self
.
course
.
id
# `administrative_accesses_to_course_for_user` returns accesses in tuple as
# (`global_staff`, `course_staff`, `course_instructor`).
# Order matters here, for example `True` at first index in tuple essentially means
# given user is a global staff.
for
count
,
user
in
enumerate
([
self
.
global_staff
,
self
.
course_staff
,
self
.
course_instructor
]):
self
.
assertTrue
(
access
.
administrative_accesses_to_course_for_user
(
user
,
course_key
)[
count
])
self
.
assertFalse
(
any
(
access
.
administrative_accesses_to_course_for_user
(
self
.
student
,
course_key
)))
def
test_student_has_access
(
self
):
def
test_student_has_access
(
self
):
"""
"""
...
@@ -264,15 +261,6 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -264,15 +261,6 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
for
obj
in
modules
:
for
obj
in
modules
:
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'load'
,
obj
,
course_key
=
self
.
course
.
id
)))
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'load'
,
obj
,
course_key
=
self
.
course
.
id
)))
def
test_string_has_staff_access_to_preview_mode
(
self
):
"""
Tests different users has right access to string content in preview mode.
"""
self
.
assertTrue
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
global_staff
,
obj
=
'global'
)))
self
.
assertFalse
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
course_staff
,
obj
=
'global'
)))
self
.
assertFalse
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
course_instructor
,
obj
=
'global'
)))
self
.
assertFalse
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
student
,
obj
=
'global'
)))
@patch
(
'courseware.access.in_preview_mode'
,
Mock
(
return_value
=
True
))
@patch
(
'courseware.access.in_preview_mode'
,
Mock
(
return_value
=
True
))
def
test_has_access_with_preview_mode
(
self
):
def
test_has_access_with_preview_mode
(
self
):
"""
"""
...
@@ -286,17 +274,17 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
...
@@ -286,17 +274,17 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'load'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'load'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
#
User should be able to preview when masquerade.
#
When masquerading is true, user should not be able to access staff content
with
patch
(
'courseware.access.is_masquerading_as_student'
)
as
mock_masquerade
:
with
patch
(
'courseware.access.is_masquerading_as_student'
)
as
mock_masquerade
:
mock_masquerade
.
return_value
=
True
mock_masquerade
.
return_value
=
True
self
.
assert
Tru
e
(
self
.
assert
Fals
e
(
bool
(
access
.
has_access
(
self
.
global_staff
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
))
bool
(
access
.
has_access
(
self
.
global_staff
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
))
)
)
self
.
assertFalse
(
self
.
assertFalse
(
bool
(
access
.
has_access
(
self
.
student
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
))
bool
(
access
.
has_access
(
self
.
student
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
))
)
)
@patch
(
'courseware.access.in_preview_mode'
,
Mock
(
return_value
=
True
))
@patch
(
'courseware.access
_utils
.in_preview_mode'
,
Mock
(
return_value
=
True
))
def
test_has_access_in_preview_mode_with_group
(
self
):
def
test_has_access_in_preview_mode_with_group
(
self
):
"""
"""
Test that a user masquerading as a member of a group sees appropriate content in preview mode.
Test that a user masquerading as a member of a group sees appropriate content in preview mode.
...
@@ -851,7 +839,10 @@ class CourseOverviewAccessTestCase(ModuleStoreTestCase):
...
@@ -851,7 +839,10 @@ class CourseOverviewAccessTestCase(ModuleStoreTestCase):
user
=
getattr
(
self
,
user_attr_name
)
user
=
getattr
(
self
,
user_attr_name
)
user
=
User
.
objects
.
get
(
id
=
user
.
id
)
user
=
User
.
objects
.
get
(
id
=
user
.
id
)
if
user_attr_name
==
'user_staff'
and
action
==
'see_exists'
and
course_attr_name
==
'course_not_started'
:
if
(
user_attr_name
==
'user_staff'
and
action
==
'see_exists'
and
course_attr_name
in
[
'course_default'
,
'course_not_started'
]):
# checks staff role
# checks staff role
num_queries
=
1
num_queries
=
1
elif
user_attr_name
==
'user_normal'
and
action
==
'see_exists'
and
course_attr_name
!=
'course_started'
:
elif
user_attr_name
==
'user_normal'
and
action
==
'see_exists'
and
course_attr_name
!=
'course_started'
:
...
...
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