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
1e460073
Commit
1e460073
authored
Mar 17, 2016
by
muzaffaryousaf
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Restrice non-staff users to access preview content.
TNL-4194
parent
eebae966
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
175 additions
and
25 deletions
+175
-25
lms/djangoapps/courseware/access.py
+54
-1
lms/djangoapps/courseware/tests/test_access.py
+121
-24
No files found.
lms/djangoapps/courseware/access.py
View file @
1e460073
...
...
@@ -60,7 +60,10 @@ from courseware.access_response import (
MobileAvailabilityError
,
VisibilityError
,
)
from
courseware.access_utils
import
adjust_start_date
,
check_start_date
,
debug
,
ACCESS_GRANTED
,
ACCESS_DENIED
from
courseware.access_utils
import
(
adjust_start_date
,
check_start_date
,
debug
,
ACCESS_GRANTED
,
ACCESS_DENIED
,
in_preview_mode
)
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -102,6 +105,10 @@ def has_access(user, action, obj, course_key=None):
if
isinstance
(
course_key
,
CCXLocator
):
course_key
=
course_key
.
to_course_locator
()
if
in_preview_mode
():
if
not
bool
(
has_staff_access_to_preview_mode
(
user
=
user
,
obj
=
obj
,
course_key
=
course_key
)):
return
ACCESS_DENIED
# delegate the work to type-specific functions.
# (start with more specific types, then get more general)
if
isinstance
(
obj
,
CourseDescriptor
):
...
...
@@ -139,6 +146,52 @@ def has_access(user, action, obj, course_key=None):
# ================ Implementation helpers ================================
def
has_staff_access_to_preview_mode
(
user
,
obj
,
course_key
=
None
):
"""
Returns whether user has staff access to specified modules or not.
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
:
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
):
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
"""
Checks if a user has access to a descriptor based on its start date.
...
...
lms/djangoapps/courseware/tests/test_access.py
View file @
1e460073
...
...
@@ -12,6 +12,9 @@ from django.core.urlresolvers import reverse
from
mock
import
Mock
,
patch
from
nose.plugins.attrib
import
attr
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
ccx_keys.locator
import
CCXLocator
from
ccx.tests.factories
import
CcxFactory
import
courseware.access
as
access
import
courseware.access_response
as
access_response
...
...
@@ -35,8 +38,15 @@ from xmodule.course_module import (
CATALOG_VISIBILITY_ABOUT
,
CATALOG_VISIBILITY_NONE
,
)
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.error_module
import
ErrorDescriptor
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.django_utils
import
(
ModuleStoreTestCase
,
SharedModuleStoreTestCase
,
TEST_DATA_SPLIT_MODULESTORE
)
from
xmodule.modulestore.xml
import
CourseLocationManager
from
xmodule.tests
import
get_test_system
from
util.milestones_helpers
import
(
set_prerequisite_courses
,
...
...
@@ -55,23 +65,23 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
"""
TOMORROW
=
datetime
.
datetime
.
now
(
pytz
.
utc
)
+
datetime
.
timedelta
(
days
=
1
)
YESTERDAY
=
datetime
.
datetime
.
now
(
pytz
.
utc
)
-
datetime
.
timedelta
(
days
=
1
)
MODULESTORE
=
TEST_DATA_SPLIT_MODULESTORE
def
setUp
(
self
):
super
(
AccessTestCase
,
self
)
.
setUp
()
course_key
=
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
)
self
.
course
=
course_key
.
make_usage_key
(
'course'
,
course_key
.
run
)
self
.
course
=
CourseFactory
.
create
(
org
=
'edX'
,
course
=
'toy'
,
run
=
'test_run'
)
self
.
anonymous_user
=
AnonymousUserFactory
()
self
.
beta_user
=
BetaTesterFactory
(
course_key
=
self
.
course
.
course_key
)
self
.
beta_user
=
BetaTesterFactory
(
course_key
=
self
.
course
.
id
)
self
.
student
=
UserFactory
()
self
.
global_staff
=
UserFactory
(
is_staff
=
True
)
self
.
course_staff
=
StaffFactory
(
course_key
=
self
.
course
.
course_key
)
self
.
course_instructor
=
InstructorFactory
(
course_key
=
self
.
course
.
course_key
)
self
.
course_staff
=
StaffFactory
(
course_key
=
self
.
course
.
id
)
self
.
course_instructor
=
InstructorFactory
(
course_key
=
self
.
course
.
id
)
self
.
staff
=
GlobalStaffFactory
()
def
verify_access
(
self
,
mock_unit
,
student_should_have_access
,
expected_error_type
=
None
):
""" Verify the expected result from _has_access_descriptor """
response
=
access
.
_has_access_descriptor
(
self
.
anonymous_user
,
'load'
,
mock_unit
,
course_key
=
self
.
course
.
course_key
)
mock_unit
,
course_key
=
self
.
course
.
id
)
self
.
assertEqual
(
student_should_have_access
,
bool
(
response
))
if
expected_error_type
is
not
None
:
...
...
@@ -79,55 +89,142 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
self
.
assertIsNotNone
(
response
.
to_json
()[
'error_code'
])
self
.
assertTrue
(
access
.
_has_access_descriptor
(
self
.
course_staff
,
'load'
,
mock_unit
,
course_key
=
self
.
course
.
course_key
)
access
.
_has_access_descriptor
(
self
.
course_staff
,
'load'
,
mock_unit
,
course_key
=
self
.
course
.
id
)
)
def
test_has_staff_access_to_preview_mode
(
self
):
"""
Tests users have right access to content in preview mode.
"""
course_key
=
self
.
course
.
id
usage_key
=
self
.
course
.
scope_ids
.
usage_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
)
ccx_locator
=
CCXLocator
.
from_course_locator
(
course_key
,
ccx
.
id
)
error_descriptor
=
ErrorDescriptor
.
from_xml
(
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
=
[
self
.
course
,
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
]:
for
obj
in
modules
:
self
.
assertTrue
(
bool
(
access
.
has_staff_access_to_preview_mode
(
user
,
obj
=
obj
)))
self
.
assertFalse
(
bool
(
access
.
has_staff_access_to_preview_mode
(
self
.
student
,
obj
=
obj
)))
def
test_student_has_access
(
self
):
"""
Tests course student have right access to content w/o preview.
"""
course_key
=
self
.
course
.
id
chapter
=
ItemFactory
.
create
(
category
=
"chapter"
,
parent_location
=
self
.
course
.
location
)
overview
=
CourseOverview
.
get_from_id
(
course_key
)
# Enroll student to the course
CourseEnrollmentFactory
(
user
=
self
.
student
,
course_id
=
self
.
course
.
id
)
modules
=
[
self
.
course
,
overview
,
chapter
,
]
with
patch
(
'courseware.access.in_preview_mode'
)
as
mock_preview
:
mock_preview
.
return_value
=
False
for
obj
in
modules
:
self
.
assertTrue
(
bool
(
access
.
has_access
(
self
.
student
,
'load'
,
obj
,
course_key
=
self
.
course
.
id
)))
with
patch
(
'courseware.access.in_preview_mode'
)
as
mock_preview
:
mock_preview
.
return_value
=
True
for
obj
in
modules
:
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
))
def
test_has_access_with_preview_mode
(
self
):
"""
Tests particular user's can access content via has_access in preview mode.
"""
self
.
assertTrue
(
bool
(
access
.
has_access
(
self
.
global_staff
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
self
.
assertTrue
(
bool
(
access
.
has_access
(
self
.
course_staff
,
'staff'
,
self
.
course
,
course_key
=
self
.
course
.
id
)))
self
.
assertTrue
(
bool
(
access
.
has_access
(
self
.
course_instructor
,
'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
)))
def
test_has_access_to_course
(
self
):
self
.
assertFalse
(
access
.
_has_access_to_course
(
None
,
'staff'
,
self
.
course
.
course_key
None
,
'staff'
,
self
.
course
.
id
))
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
anonymous_user
,
'staff'
,
self
.
course
.
course_key
self
.
anonymous_user
,
'staff'
,
self
.
course
.
id
))
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
anonymous_user
,
'instructor'
,
self
.
course
.
course_key
self
.
anonymous_user
,
'instructor'
,
self
.
course
.
id
))
self
.
assertTrue
(
access
.
_has_access_to_course
(
self
.
global_staff
,
'staff'
,
self
.
course
.
course_key
self
.
global_staff
,
'staff'
,
self
.
course
.
id
))
self
.
assertTrue
(
access
.
_has_access_to_course
(
self
.
global_staff
,
'instructor'
,
self
.
course
.
course_key
self
.
global_staff
,
'instructor'
,
self
.
course
.
id
))
# A user has staff access if they are in the staff group
self
.
assertTrue
(
access
.
_has_access_to_course
(
self
.
course_staff
,
'staff'
,
self
.
course
.
course_key
self
.
course_staff
,
'staff'
,
self
.
course
.
id
))
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
course_staff
,
'instructor'
,
self
.
course
.
course_key
self
.
course_staff
,
'instructor'
,
self
.
course
.
id
))
# A user has staff and instructor access if they are in the instructor group
self
.
assertTrue
(
access
.
_has_access_to_course
(
self
.
course_instructor
,
'staff'
,
self
.
course
.
course_key
self
.
course_instructor
,
'staff'
,
self
.
course
.
id
))
self
.
assertTrue
(
access
.
_has_access_to_course
(
self
.
course_instructor
,
'instructor'
,
self
.
course
.
course_key
self
.
course_instructor
,
'instructor'
,
self
.
course
.
id
))
# A user does not have staff or instructor access if they are
# not in either the staff or the the instructor group
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
student
,
'staff'
,
self
.
course
.
course_key
self
.
student
,
'staff'
,
self
.
course
.
id
))
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
student
,
'instructor'
,
self
.
course
.
course_key
self
.
student
,
'instructor'
,
self
.
course
.
id
))
self
.
assertFalse
(
access
.
_has_access_to_course
(
self
.
student
,
'not_staff_or_instructor'
,
self
.
course
.
course_key
self
.
student
,
'not_staff_or_instructor'
,
self
.
course
.
id
))
def
test__has_access_string
(
self
):
...
...
@@ -154,12 +251,12 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
(
self
.
course_instructor
,
expected_instructor
)
):
self
.
assertEquals
(
bool
(
access
.
_has_access_error_desc
(
user
,
action
,
descriptor
,
self
.
course
.
course_key
)),
bool
(
access
.
_has_access_error_desc
(
user
,
action
,
descriptor
,
self
.
course
.
id
)),
expected_response
)
with
self
.
assertRaises
(
ValueError
):
access
.
_has_access_error_desc
(
self
.
course_instructor
,
'not_load_or_staff'
,
descriptor
,
self
.
course
.
course_key
)
access
.
_has_access_error_desc
(
self
.
course_instructor
,
'not_load_or_staff'
,
descriptor
,
self
.
course
.
id
)
def
test__has_access_descriptor
(
self
):
# TODO: override DISABLE_START_DATES and test the start date branch of the method
...
...
@@ -202,7 +299,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
mock_unit
.
visible_to_staff_only
=
False
self
.
assertTrue
(
bool
(
access
.
_has_access_descriptor
(
self
.
beta_user
,
'load'
,
mock_unit
,
course_key
=
self
.
course
.
course_key
)))
self
.
beta_user
,
'load'
,
mock_unit
,
course_key
=
self
.
course
.
id
)))
@ddt.data
(
None
,
YESTERDAY
,
TOMORROW
)
@patch.dict
(
'django.conf.settings.FEATURES'
,
{
'DISABLE_START_DATES'
:
False
})
...
...
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