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
ad939b1e
Commit
ad939b1e
authored
Sep 24, 2013
by
jkarni
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1090 from edx/jkarni/feature/middleware-locked-assets
Jkarni/feature/middleware locked assets
parents
73e03883
1a0b752a
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
209 additions
and
4 deletions
+209
-4
cms/envs/common.py
+1
-1
common/djangoapps/contentserver/middleware.py
+11
-2
common/djangoapps/contentserver/tests/__init__.py
+0
-0
common/djangoapps/contentserver/tests/test.py
+136
-0
common/djangoapps/student/models.py
+25
-0
common/djangoapps/student/tests/tests.py
+11
-0
common/test/data/toy/static/another_static.txt
+17
-0
lms/envs/common.py
+1
-1
lms/envs/test.py
+7
-0
No files found.
cms/envs/common.py
View file @
ad939b1e
...
...
@@ -140,7 +140,6 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES
=
(
'contentserver.middleware.StaticContentServer'
,
'request_cache.middleware.RequestCache'
,
'django.middleware.cache.UpdateCacheMiddleware'
,
'django.middleware.common.CommonMiddleware'
,
...
...
@@ -150,6 +149,7 @@ MIDDLEWARE_CLASSES = (
# Instead of AuthenticationMiddleware, we use a cache-backed version
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware'
,
'contentserver.middleware.StaticContentServer'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'track.middleware.TrackMiddleware'
,
...
...
common/djangoapps/contentserver/middleware.py
View file @
ad939b1e
from
django.http
import
HttpResponse
,
HttpResponseNotModified
from
django.http
import
(
HttpResponse
,
HttpResponseNotModified
,
HttpResponseForbidden
)
from
student.models
import
CourseEnrollment
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.content
import
StaticContent
,
XASSET_LOCATION_TAG
...
...
@@ -41,7 +43,14 @@ class StaticContentServer(object):
# NOP here, but we may wish to add a "cache-hit" counter in the future
pass
# see if the last-modified at hasn't changed, if not return a 302 (Not Modified)
# Check that user has access to content
if
getattr
(
content
,
"locked"
,
False
):
if
not
hasattr
(
request
,
"user"
)
or
not
request
.
user
.
is_authenticated
():
return
HttpResponseForbidden
(
'Unauthorized'
)
course_partial_id
=
"/"
.
join
([
loc
.
org
,
loc
.
course
])
if
not
request
.
user
.
is_staff
and
not
CourseEnrollment
.
is_enrolled_by_partial
(
request
.
user
,
course_partial_id
):
return
HttpResponseForbidden
(
'Unauthorized'
)
# convert over the DB persistent last modified timestamp to a HTTP compatible
# timestamp, so we can simply compare the strings
...
...
common/djangoapps/contentserver/tests/__init__.py
0 → 100644
View file @
ad939b1e
common/djangoapps/contentserver/tests/test.py
0 → 100644
View file @
ad939b1e
"""
Tests for StaticContentServer
"""
import
copy
import
logging
from
uuid
import
uuid4
from
path
import
path
from
pymongo
import
MongoClient
from
django.contrib.auth.models
import
User
from
django.conf
import
settings
from
django.test.client
import
Client
from
django.test.utils
import
override_settings
from
student.models
import
CourseEnrollment
from
xmodule.contentstore.django
import
contentstore
,
_CONTENTSTORE
from
xmodule.modulestore
import
Location
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
(
studio_store_config
,
ModuleStoreTestCase
)
from
xmodule.modulestore.xml_importer
import
import_from_xml
log
=
logging
.
getLogger
(
__name__
)
TEST_DATA_CONTENTSTORE
=
copy
.
deepcopy
(
settings
.
CONTENTSTORE
)
TEST_DATA_CONTENTSTORE
[
'OPTIONS'
][
'db'
]
=
'test_xcontent_
%
s'
%
uuid4
()
.
hex
TEST_MODULESTORE
=
studio_store_config
(
settings
.
TEST_ROOT
/
"data"
)
@override_settings
(
CONTENTSTORE
=
TEST_DATA_CONTENTSTORE
,
MODULESTORE
=
TEST_MODULESTORE
)
class
ContentStoreToyCourseTest
(
ModuleStoreTestCase
):
"""
Tests that use the toy course.
"""
def
setUp
(
self
):
"""
Create user and login.
"""
settings
.
MODULESTORE
[
'default'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
settings
.
MODULESTORE
[
'direct'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
self
.
client
=
Client
()
self
.
contentstore
=
contentstore
()
# A locked asset
self
.
loc_locked
=
Location
(
'c4x'
,
'edX'
,
'toy'
,
'asset'
,
'sample_static.txt'
)
self
.
url_locked
=
StaticContent
.
get_url_path_from_location
(
self
.
loc_locked
)
# An unlocked asset
self
.
loc_unlocked
=
Location
(
'c4x'
,
'edX'
,
'toy'
,
'asset'
,
'another_static.txt'
)
self
.
url_unlocked
=
StaticContent
.
get_url_path_from_location
(
self
.
loc_unlocked
)
import_from_xml
(
modulestore
(
'direct'
),
'common/test/data/'
,
[
'toy'
],
static_content_store
=
self
.
contentstore
,
verbose
=
True
)
self
.
contentstore
.
set_attr
(
self
.
loc_locked
,
'locked'
,
True
)
# Create user
self
.
usr
=
'testuser'
self
.
pwd
=
'foo'
email
=
'test+courses@edx.org'
self
.
user
=
User
.
objects
.
create_user
(
self
.
usr
,
email
,
self
.
pwd
)
self
.
user
.
is_active
=
True
self
.
user
.
save
()
# Create staff user
self
.
staff_usr
=
'stafftestuser'
self
.
staff_pwd
=
'foo'
staff_email
=
'stafftest+courses@edx.org'
self
.
staff_user
=
User
.
objects
.
create_user
(
self
.
staff_usr
,
staff_email
,
self
.
staff_pwd
)
self
.
staff_user
.
is_active
=
True
self
.
staff_user
.
is_staff
=
True
self
.
staff_user
.
save
()
def
tearDown
(
self
):
MongoClient
()
.
drop_database
(
TEST_DATA_CONTENTSTORE
[
'OPTIONS'
][
'db'
])
_CONTENTSTORE
.
clear
()
def
test_unlocked_asset
(
self
):
"""
Test that unlocked assets are being served.
"""
self
.
client
.
logout
()
resp
=
self
.
client
.
get
(
self
.
url_unlocked
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
#pylint: disable=E1103
def
test_locked_asset_not_logged_in
(
self
):
"""
Test that locked assets behave appropriately in case the user is not
logged in.
"""
self
.
client
.
logout
()
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
403
)
#pylint: disable=E1103
def
test_locked_asset_not_registered
(
self
):
"""
Test that locked assets behave appropriately in case user is logged in
in but not registered for the course.
"""
self
.
client
.
login
(
username
=
self
.
usr
,
password
=
self
.
pwd
)
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
403
)
#pylint: disable=E1103
def
test_locked_asset_registered
(
self
):
"""
Test that locked assets behave appropriately in case user is logged in
and registered for the course.
"""
#pylint: disable=E1101
course_id
=
"/"
.
join
([
self
.
loc_locked
.
org
,
self
.
loc_locked
.
course
,
'2012_Fall'
])
CourseEnrollment
.
enroll
(
self
.
user
,
course_id
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
course_id
))
self
.
client
.
login
(
username
=
self
.
usr
,
password
=
self
.
pwd
)
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
#pylint: disable=E1103
def
test_locked_asset_staff
(
self
):
"""
Test that locked assets behave appropriately in case user is staff.
"""
#pylint: disable=E1101
course_id
=
"/"
.
join
([
self
.
loc_locked
.
org
,
self
.
loc_locked
.
course
,
'2012_Fall'
])
self
.
client
.
login
(
username
=
self
.
staff_usr
,
password
=
self
.
staff_pwd
)
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
#pylint: disable=E1103
common/djangoapps/student/models.py
View file @
ad939b1e
...
...
@@ -844,6 +844,31 @@ class CourseEnrollment(models.Model):
return
False
@classmethod
def
is_enrolled_by_partial
(
cls
,
user
,
course_id_partial
):
"""
Returns `True` if the user is enrolled in a course that starts with
`course_id_partial`. Otherwise, returns False.
Can be used to determine whether a student is enrolled in a course
whose run name is unknown.
`user` is a Django User object. If it hasn't been saved yet (no `.id`
attribute), this method will automatically save it before
adding an enrollment for it.
`course_id_partial` is a starting substring for a fully qualified
course_id (e.g. "edX/Test101/").
"""
try
:
return
CourseEnrollment
.
objects
.
filter
(
user
=
user
,
course_id__startswith
=
course_id_partial
,
is_active
=
1
)
.
exists
()
except
cls
.
DoesNotExist
:
return
False
@classmethod
def
enrollment_mode_for_user
(
cls
,
user
,
course_id
):
"""
Returns the enrollment mode for the given user for the given course
...
...
common/djangoapps/student/tests/tests.py
View file @
ad939b1e
...
...
@@ -213,23 +213,34 @@ class EnrollInCourseTest(TestCase):
def
test_enrollment
(
self
):
user
=
User
.
objects
.
create_user
(
"joe"
,
"joe@joe.com"
,
"password"
)
course_id
=
"edX/Test101/2013"
course_id_partial
=
"edX/Test101"
# Test basic enrollment
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled
(
user
,
course_id
))
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled_by_partial
(
user
,
course_id_partial
))
CourseEnrollment
.
enroll
(
user
,
course_id
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
user
,
course_id
))
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled_by_partial
(
user
,
course_id_partial
))
# Enrolling them again should be harmless
CourseEnrollment
.
enroll
(
user
,
course_id
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
user
,
course_id
))
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled_by_partial
(
user
,
course_id_partial
))
# Now unenroll the user
CourseEnrollment
.
unenroll
(
user
,
course_id
)
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled
(
user
,
course_id
))
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled_by_partial
(
user
,
course_id_partial
))
# Unenrolling them again should also be harmless
CourseEnrollment
.
unenroll
(
user
,
course_id
)
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled
(
user
,
course_id
))
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled_by_partial
(
user
,
course_id_partial
))
# The enrollment record should still exist, just be inactive
enrollment_record
=
CourseEnrollment
.
objects
.
get
(
...
...
common/test/data/toy/static/another_static.txt
0 → 100644
View file @
ad939b1e
_
| |
_____ ____ _ _ __ ___ _ __ | | ___
/ _ \ \/ / _` | '_ ` _ \| '_ \| |/ _ \
| __/> < (_| | | | | | | |_) | | __/
\___/_/\_\__,_|_| |_| |_| .__/|_|\___|
| |
|_|
_ _ _
| | | | (_)
___| |_ __ _| |_ _ ___
/ __| __/ _` | __| |/ __|
\__ \ || (_| | |_| | (__
|___/\__\__,_|\__|_|\___|
lms/envs/common.py
View file @
ad939b1e
...
...
@@ -542,7 +542,6 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES
=
(
'contentserver.middleware.StaticContentServer'
,
'request_cache.middleware.RequestCache'
,
'django_comment_client.middleware.AjaxExceptionMiddleware'
,
'django.middleware.common.CommonMiddleware'
,
...
...
@@ -551,6 +550,7 @@ MIDDLEWARE_CLASSES = (
# Instead of AuthenticationMiddleware, we use a cached backed version
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware'
,
'contentserver.middleware.StaticContentServer'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'track.middleware.TrackMiddleware'
,
...
...
lms/envs/test.py
View file @
ad939b1e
...
...
@@ -97,6 +97,13 @@ MODULESTORE = {
}
}
CONTENTSTORE
=
{
'ENGINE'
:
'xmodule.contentstore.mongo.MongoContentStore'
,
'OPTIONS'
:
{
'host'
:
'localhost'
,
'db'
:
'xcontent'
,
}
}
DATABASES
=
{
'default'
:
{
...
...
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