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
2c41d79c
Commit
2c41d79c
authored
Jun 22, 2016
by
Kevin Falcone
Committed by
GitHub
Jun 22, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12827 from edx/release
Release -> Master after revert
parents
d7c570aa
a5a235bd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
35 additions
and
171 deletions
+35
-171
cms/djangoapps/contentstore/tests/test_contentstore.py
+2
-2
cms/djangoapps/contentstore/tests/utils.py
+1
-1
cms/djangoapps/contentstore/views/tests/test_assets.py
+4
-4
common/djangoapps/contentserver/middleware.py
+7
-28
common/djangoapps/contentserver/test/test_contentserver.py
+2
-54
common/djangoapps/static_replace/test/test_static_replace.py
+0
-0
common/lib/xmodule/xmodule/contentstore/content.py
+17
-78
common/lib/xmodule/xmodule/contentstore/mongo.py
+2
-4
common/test/data/toy/static/sample_static.txt
+0
-0
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
2c41d79c
...
@@ -1000,7 +1000,7 @@ class MiscCourseTests(ContentStoreTestCase):
...
@@ -1000,7 +1000,7 @@ class MiscCourseTests(ContentStoreTestCase):
3) computing thumbnail location of asset
3) computing thumbnail location of asset
4) deleting the asset from the course
4) deleting the asset from the course
"""
"""
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
html
'
)
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
txt
'
)
content
=
StaticContent
(
content
=
StaticContent
(
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
)
)
...
@@ -1072,7 +1072,7 @@ class MiscCourseTests(ContentStoreTestCase):
...
@@ -1072,7 +1072,7 @@ class MiscCourseTests(ContentStoreTestCase):
draft content is also deleted
draft content is also deleted
"""
"""
# add an asset
# add an asset
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
html
'
)
asset_key
=
self
.
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
txt
'
)
content
=
StaticContent
(
content
=
StaticContent
(
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
asset_key
,
"Fake asset"
,
"application/text"
,
"test"
,
)
)
...
...
cms/djangoapps/contentstore/tests/utils.py
View file @
2c41d79c
...
@@ -121,7 +121,7 @@ class CourseTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase):
...
@@ -121,7 +121,7 @@ class CourseTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase):
SEQUENTIAL
=
'vertical_sequential'
SEQUENTIAL
=
'vertical_sequential'
DRAFT_HTML
=
'draft_html'
DRAFT_HTML
=
'draft_html'
DRAFT_VIDEO
=
'draft_video'
DRAFT_VIDEO
=
'draft_video'
LOCKED_ASSET_KEY
=
AssetLocation
.
from_deprecated_string
(
'/c4x/edX/toy/asset/sample_static.
html
'
)
LOCKED_ASSET_KEY
=
AssetLocation
.
from_deprecated_string
(
'/c4x/edX/toy/asset/sample_static.
txt
'
)
def
import_and_populate_course
(
self
):
def
import_and_populate_course
(
self
):
"""
"""
...
...
cms/djangoapps/contentstore/views/tests/test_assets.py
View file @
2c41d79c
...
@@ -126,7 +126,7 @@ class BasicAssetsTestCase(AssetsTestCase):
...
@@ -126,7 +126,7 @@ class BasicAssetsTestCase(AssetsTestCase):
)
)
course
=
module_store
.
get_course
(
course_id
)
course
=
module_store
.
get_course
(
course_id
)
filename
=
'sample_static.
html
'
filename
=
'sample_static.
txt
'
html_src_attribute
=
'"/static/{}"'
.
format
(
filename
)
html_src_attribute
=
'"/static/{}"'
.
format
(
filename
)
asset_url
=
replace_static_urls
(
html_src_attribute
,
course_id
=
course
.
id
)
asset_url
=
replace_static_urls
(
html_src_attribute
,
course_id
=
course
.
id
)
url
=
asset_url
.
replace
(
'"'
,
''
)
url
=
asset_url
.
replace
(
'"'
,
''
)
...
@@ -379,7 +379,7 @@ class LockAssetTestCase(AssetsTestCase):
...
@@ -379,7 +379,7 @@ class LockAssetTestCase(AssetsTestCase):
"""
"""
def
verify_asset_locked_state
(
locked
):
def
verify_asset_locked_state
(
locked
):
""" Helper method to verify lock state in the contentstore """
""" Helper method to verify lock state in the contentstore """
asset_location
=
StaticContent
.
get_location_from_path
(
'/c4x/edX/toy/asset/sample_static.
html
'
)
asset_location
=
StaticContent
.
get_location_from_path
(
'/c4x/edX/toy/asset/sample_static.
txt
'
)
content
=
contentstore
()
.
find
(
asset_location
)
content
=
contentstore
()
.
find
(
asset_location
)
self
.
assertEqual
(
content
.
locked
,
locked
)
self
.
assertEqual
(
content
.
locked
,
locked
)
...
@@ -387,14 +387,14 @@ class LockAssetTestCase(AssetsTestCase):
...
@@ -387,14 +387,14 @@ class LockAssetTestCase(AssetsTestCase):
""" Helper method for posting asset update. """
""" Helper method for posting asset update. """
content_type
=
'application/txt'
content_type
=
'application/txt'
upload_date
=
datetime
(
2013
,
6
,
1
,
10
,
30
,
tzinfo
=
UTC
)
upload_date
=
datetime
(
2013
,
6
,
1
,
10
,
30
,
tzinfo
=
UTC
)
asset_location
=
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
html
'
)
asset_location
=
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.
txt
'
)
url
=
reverse_course_url
(
'assets_handler'
,
course
.
id
,
kwargs
=
{
'asset_key_string'
:
unicode
(
asset_location
)})
url
=
reverse_course_url
(
'assets_handler'
,
course
.
id
,
kwargs
=
{
'asset_key_string'
:
unicode
(
asset_location
)})
resp
=
self
.
client
.
post
(
resp
=
self
.
client
.
post
(
url
,
url
,
# pylint: disable=protected-access
# pylint: disable=protected-access
json
.
dumps
(
assets
.
_get_asset_json
(
json
.
dumps
(
assets
.
_get_asset_json
(
"sample_static.
html
"
,
content_type
,
upload_date
,
asset_location
,
None
,
lock
)),
"sample_static.
txt
"
,
content_type
,
upload_date
,
asset_location
,
None
,
lock
)),
"application/json"
"application/json"
)
)
...
...
common/djangoapps/contentserver/middleware.py
View file @
2c41d79c
...
@@ -3,11 +3,12 @@ Middleware to serve assets.
...
@@ -3,11 +3,12 @@ Middleware to serve assets.
"""
"""
import
logging
import
logging
import
datetime
import
datetime
import
newrelic.agent
import
newrelic.agent
from
django.http
import
(
from
django.http
import
(
HttpResponse
,
HttpResponseNotModified
,
HttpResponseForbidden
,
HttpResponse
,
HttpResponseNotModified
,
HttpResponseForbidden
,
HttpResponseBadRequest
,
HttpResponseNotFound
,
HttpResponsePermanentRedirect
)
HttpResponseBadRequest
,
HttpResponseNotFound
)
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
from
contentserver.models
import
CourseAssetCacheTtlConfig
,
CdnUserAgentsConfig
from
contentserver.models
import
CourseAssetCacheTtlConfig
,
CdnUserAgentsConfig
...
@@ -29,54 +30,32 @@ HTTP_DATE_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
...
@@ -29,54 +30,32 @@ HTTP_DATE_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
class
StaticContentServer
(
object
):
class
StaticContentServer
(
object
):
"""
Serves course assets to end users. Colloquially referred to as "contentserver."
"""
def
is_asset_request
(
self
,
request
):
def
is_asset_request
(
self
,
request
):
"""Determines whether the given request is an asset request"""
"""Determines whether the given request is an asset request"""
return
(
return
(
request
.
path
.
startswith
(
'/'
+
XASSET_LOCATION_TAG
+
'/'
)
request
.
path
.
startswith
(
'/'
+
XASSET_LOCATION_TAG
+
'/'
)
or
or
request
.
path
.
startswith
(
'/'
+
AssetLocator
.
CANONICAL_NAMESPACE
)
request
.
path
.
startswith
(
'/'
+
AssetLocator
.
CANONICAL_NAMESPACE
)
or
StaticContent
.
is_versioned_asset_path
(
request
.
path
)
)
)
def
process_request
(
self
,
request
):
def
process_request
(
self
,
request
):
"""Process the given request"""
"""Process the given request"""
asset_path
=
request
.
path
if
self
.
is_asset_request
(
request
):
if
self
.
is_asset_request
(
request
):
# Make sure we can convert this request into a location.
# Make sure we can convert this request into a location.
if
AssetLocator
.
CANONICAL_NAMESPACE
in
asset_path
:
if
AssetLocator
.
CANONICAL_NAMESPACE
in
request
.
path
:
asset_path
=
asset_path
.
replace
(
'block/'
,
'block@'
,
1
)
request
.
path
=
request
.
path
.
replace
(
'block/'
,
'block@'
,
1
)
# If this is a versioned request, pull out the digest and chop off the prefix.
requested_digest
=
None
if
StaticContent
.
is_versioned_asset_path
(
asset_path
):
requested_digest
,
asset_path
=
StaticContent
.
parse_versioned_asset_path
(
asset_path
)
# Make sure we have a valid location value for this asset.
try
:
try
:
loc
=
StaticContent
.
get_location_from_path
(
asset_
path
)
loc
=
StaticContent
.
get_location_from_path
(
request
.
path
)
except
(
InvalidLocationError
,
InvalidKeyError
):
except
(
InvalidLocationError
,
InvalidKeyError
):
return
HttpResponseBadRequest
()
return
HttpResponseBadRequest
()
# Attempt to load the asset to make sure it exists, and grab the asset digest
# Try and load the asset.
# if we're able to load it.
content
=
None
actual_digest
=
None
try
:
try
:
content
=
self
.
load_asset_from_location
(
loc
)
content
=
self
.
load_asset_from_location
(
loc
)
actual_digest
=
content
.
content_digest
except
(
ItemNotFoundError
,
NotFoundError
):
except
(
ItemNotFoundError
,
NotFoundError
):
return
HttpResponseNotFound
()
return
HttpResponseNotFound
()
# If this was a versioned asset, and the digest doesn't match, redirect
# them to the actual version.
if
requested_digest
is
not
None
and
(
actual_digest
!=
requested_digest
):
actual_asset_path
=
StaticContent
.
add_version_to_asset_path
(
asset_path
,
actual_digest
)
return
HttpResponsePermanentRedirect
(
actual_asset_path
)
# Set the basics for this request. Make sure that the course key for this
# Set the basics for this request. Make sure that the course key for this
# asset has a run, which old-style courses do not. Otherwise, this will
# asset has a run, which old-style courses do not. Otherwise, this will
# explode when the key is serialized to be sent to NR.
# explode when the key is serialized to be sent to NR.
...
...
common/djangoapps/contentserver/test/test_contentserver.py
View file @
2c41d79c
...
@@ -16,13 +16,9 @@ from django.test.utils import override_settings
...
@@ -16,13 +16,9 @@ from django.test.utils import override_settings
from
mock
import
patch
from
mock
import
patch
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.xml_importer
import
import_course_from_xml
from
xmodule.modulestore.xml_importer
import
import_course_from_xml
from
xmodule.assetstore.assetmgr
import
AssetManager
from
opaque_keys
import
InvalidKeyError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
contentserver.middleware
import
parse_range_header
,
HTTP_DATE_FORMAT
,
StaticContentServer
from
contentserver.middleware
import
parse_range_header
,
HTTP_DATE_FORMAT
,
StaticContentServer
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
...
@@ -32,23 +28,8 @@ log = logging.getLogger(__name__)
...
@@ -32,23 +28,8 @@ log = logging.getLogger(__name__)
TEST_DATA_CONTENTSTORE
=
copy
.
deepcopy
(
settings
.
CONTENTSTORE
)
TEST_DATA_CONTENTSTORE
=
copy
.
deepcopy
(
settings
.
CONTENTSTORE
)
TEST_DATA_CONTENTSTORE
[
'DOC_STORE_CONFIG'
][
'db'
]
=
'test_xcontent_
%
s'
%
uuid4
()
.
hex
TEST_DATA_CONTENTSTORE
[
'DOC_STORE_CONFIG'
][
'db'
]
=
'test_xcontent_
%
s'
%
uuid4
()
.
hex
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
FAKE_MD5_HASH
=
'ffffffffffffffffffffffffffffffff'
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
def
get_versioned_asset_url
(
asset_path
):
"""
Creates a versioned asset URL.
"""
try
:
locator
=
StaticContent
.
get_location_from_path
(
asset_path
)
content
=
AssetManager
.
find
(
locator
,
as_stream
=
True
)
return
StaticContent
.
add_version_to_asset_path
(
asset_path
,
content
.
content_digest
)
except
(
InvalidKeyError
,
ItemNotFoundError
):
pass
return
asset_path
@ddt.ddt
@ddt.ddt
...
@@ -73,15 +54,13 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
...
@@ -73,15 +54,13 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
)
)
# A locked asset
# A locked asset
cls
.
locked_asset
=
cls
.
course_key
.
make_asset_key
(
'asset'
,
'sample_static.
html
'
)
cls
.
locked_asset
=
cls
.
course_key
.
make_asset_key
(
'asset'
,
'sample_static.
txt
'
)
cls
.
url_locked
=
unicode
(
cls
.
locked_asset
)
cls
.
url_locked
=
unicode
(
cls
.
locked_asset
)
cls
.
url_locked_versioned
=
get_versioned_asset_url
(
cls
.
url_locked
)
cls
.
contentstore
.
set_attr
(
cls
.
locked_asset
,
'locked'
,
True
)
cls
.
contentstore
.
set_attr
(
cls
.
locked_asset
,
'locked'
,
True
)
# An unlocked asset
# An unlocked asset
cls
.
unlocked_asset
=
cls
.
course_key
.
make_asset_key
(
'asset'
,
'another_static.txt'
)
cls
.
unlocked_asset
=
cls
.
course_key
.
make_asset_key
(
'asset'
,
'another_static.txt'
)
cls
.
url_unlocked
=
unicode
(
cls
.
unlocked_asset
)
cls
.
url_unlocked
=
unicode
(
cls
.
unlocked_asset
)
cls
.
url_unlocked_versioned
=
get_versioned_asset_url
(
cls
.
url_unlocked
)
cls
.
length_unlocked
=
cls
.
contentstore
.
get_attr
(
cls
.
unlocked_asset
,
'length'
)
cls
.
length_unlocked
=
cls
.
contentstore
.
get_attr
(
cls
.
unlocked_asset
,
'length'
)
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -102,37 +81,6 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
...
@@ -102,37 +81,6 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
resp
=
self
.
client
.
get
(
self
.
url_unlocked
)
resp
=
self
.
client
.
get
(
self
.
url_unlocked
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
def
test_unlocked_versioned_asset
(
self
):
"""
Test that unlocked assets that are versioned are being served.
"""
self
.
client
.
logout
()
resp
=
self
.
client
.
get
(
self
.
url_unlocked_versioned
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
def
test_unlocked_versioned_asset_with_nonexistent_version
(
self
):
"""
Test that unlocked assets that are versioned, but have a nonexistent version,
are sent back as a 301 redirect which tells the caller the correct URL.
"""
url_unlocked_versioned_old
=
StaticContent
.
add_version_to_asset_path
(
self
.
url_unlocked
,
FAKE_MD5_HASH
)
self
.
client
.
logout
()
resp
=
self
.
client
.
get
(
url_unlocked_versioned_old
)
self
.
assertEqual
(
resp
.
status_code
,
301
)
self
.
assertTrue
(
resp
.
url
.
endswith
(
self
.
url_unlocked_versioned
))
# pylint: disable=no-member
def
test_locked_versioned_asset
(
self
):
"""
Test that locked assets that are versioned are being served.
"""
CourseEnrollment
.
enroll
(
self
.
non_staff_usr
,
self
.
course_key
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
non_staff_usr
,
self
.
course_key
))
self
.
client
.
login
(
username
=
self
.
non_staff_usr
,
password
=
'test'
)
resp
=
self
.
client
.
get
(
self
.
url_locked_versioned
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
def
test_locked_asset_not_logged_in
(
self
):
def
test_locked_asset_not_logged_in
(
self
):
"""
"""
Test that locked assets behave appropriately in case the user is not
Test that locked assets behave appropriately in case the user is not
...
...
common/djangoapps/static_replace/test/test_static_replace.py
View file @
2c41d79c
This diff is collapsed.
Click to expand it.
common/lib/xmodule/xmodule/contentstore/content.py
View file @
2c41d79c
...
@@ -5,16 +5,16 @@ from xmodule.assetstore.assetmgr import AssetManager
...
@@ -5,16 +5,16 @@ from xmodule.assetstore.assetmgr import AssetManager
XASSET_LOCATION_TAG
=
'c4x'
XASSET_LOCATION_TAG
=
'c4x'
XASSET_SRCREF_PREFIX
=
'xasset:'
XASSET_SRCREF_PREFIX
=
'xasset:'
XASSET_THUMBNAIL_TAIL_NAME
=
'.jpg'
XASSET_THUMBNAIL_TAIL_NAME
=
'.jpg'
STREAM_DATA_CHUNK_SIZE
=
1024
STREAM_DATA_CHUNK_SIZE
=
1024
VERSIONED_ASSETS_PREFIX
=
'/assets/courseware'
VERSIONED_ASSETS_PATTERN
=
r'/assets/courseware/([a-f0-9]{32})'
import
os
import
os
import
logging
import
logging
import
StringIO
import
StringIO
from
urlparse
import
urlparse
,
urlunparse
,
parse_qsl
from
urlparse
import
urlparse
,
urlunparse
,
parse_qsl
from
urllib
import
urlencode
,
quote_plus
from
urllib
import
urlencode
from
opaque_keys.edx.locator
import
AssetLocator
from
opaque_keys.edx.locator
import
AssetLocator
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
...
@@ -26,7 +26,7 @@ from PIL import Image
...
@@ -26,7 +26,7 @@ from PIL import Image
class
StaticContent
(
object
):
class
StaticContent
(
object
):
def
__init__
(
self
,
loc
,
name
,
content_type
,
data
,
last_modified_at
=
None
,
thumbnail_location
=
None
,
import_path
=
None
,
def
__init__
(
self
,
loc
,
name
,
content_type
,
data
,
last_modified_at
=
None
,
thumbnail_location
=
None
,
import_path
=
None
,
length
=
None
,
locked
=
False
,
content_digest
=
None
):
length
=
None
,
locked
=
False
):
self
.
location
=
loc
self
.
location
=
loc
self
.
name
=
name
# a display string which can be edited, and thus not part of the location which needs to be fixed
self
.
name
=
name
# a display string which can be edited, and thus not part of the location which needs to be fixed
self
.
content_type
=
content_type
self
.
content_type
=
content_type
...
@@ -38,7 +38,6 @@ class StaticContent(object):
...
@@ -38,7 +38,6 @@ class StaticContent(object):
# cycles
# cycles
self
.
import_path
=
import_path
self
.
import_path
=
import_path
self
.
locked
=
locked
self
.
locked
=
locked
self
.
content_digest
=
content_digest
@property
@property
def
is_thumbnail
(
self
):
def
is_thumbnail
(
self
):
...
@@ -147,40 +146,6 @@ class StaticContent(object):
...
@@ -147,40 +146,6 @@ class StaticContent(object):
return
AssetKey
.
from_string
(
path
[
1
:])
return
AssetKey
.
from_string
(
path
[
1
:])
@staticmethod
@staticmethod
def
is_versioned_asset_path
(
path
):
"""Determines whether the given asset path is versioned."""
return
path
.
startswith
(
VERSIONED_ASSETS_PREFIX
)
@staticmethod
def
parse_versioned_asset_path
(
path
):
"""
Examines an asset path and breaks it apart if it is versioned,
returning both the asset digest and the unversioned asset path,
which will normally be an AssetKey.
"""
asset_digest
=
None
asset_path
=
path
if
StaticContent
.
is_versioned_asset_path
(
asset_path
):
result
=
re
.
match
(
VERSIONED_ASSETS_PATTERN
,
asset_path
)
if
result
is
not
None
:
asset_digest
=
result
.
groups
()[
0
]
asset_path
=
re
.
sub
(
VERSIONED_ASSETS_PATTERN
,
''
,
asset_path
)
return
(
asset_digest
,
asset_path
)
@staticmethod
def
add_version_to_asset_path
(
path
,
version
):
"""
Adds a prefix to an asset path indicating the asset's version.
"""
# Don't version an already-versioned path.
if
StaticContent
.
is_versioned_asset_path
(
path
):
return
path
return
VERSIONED_ASSETS_PREFIX
+
'/'
+
version
+
path
@staticmethod
def
get_asset_key_from_path
(
course_key
,
path
):
def
get_asset_key_from_path
(
course_key
,
path
):
"""
"""
Parses a path, extracting an asset key or creating one.
Parses a path, extracting an asset key or creating one.
...
@@ -207,16 +172,7 @@ class StaticContent(object):
...
@@ -207,16 +172,7 @@ class StaticContent(object):
return
StaticContent
.
compute_location
(
course_key
,
path
)
return
StaticContent
.
compute_location
(
course_key
,
path
)
@staticmethod
@staticmethod
def
is_excluded_asset_type
(
path
,
excluded_exts
):
def
get_canonicalized_asset_path
(
course_key
,
path
,
base_url
,
excluded_exts
):
"""
Check if this is an allowed file extension to serve.
Some files aren't served through the CDN in order to avoid same-origin policy/CORS-related issues.
"""
return
any
(
path
.
lower
()
.
endswith
(
excluded_ext
.
lower
())
for
excluded_ext
in
excluded_exts
)
@staticmethod
def
get_canonicalized_asset_path
(
course_key
,
path
,
base_url
,
excluded_exts
,
encode
=
True
):
"""
"""
Returns a fully-qualified path to a piece of static content.
Returns a fully-qualified path to a piece of static content.
...
@@ -232,27 +188,25 @@ class StaticContent(object):
...
@@ -232,27 +188,25 @@ class StaticContent(object):
"""
"""
# Break down the input path.
# Break down the input path.
_
,
_
,
relative_path
,
params
,
query_string
,
_
=
urlparse
(
path
)
_
,
_
,
relative_path
,
params
,
query_string
,
fragment
=
urlparse
(
path
)
# Convert our path to an asset key if it isn't one already.
# Convert our path to an asset key if it isn't one already.
asset_key
=
StaticContent
.
get_asset_key_from_path
(
course_key
,
relative_path
)
asset_key
=
StaticContent
.
get_asset_key_from_path
(
course_key
,
relative_path
)
# Check the status of the asset to see if this can be served via CDN aka publicly.
# Check the status of the asset to see if this can be served via CDN aka publicly.
serve_from_cdn
=
False
serve_from_cdn
=
False
content_digest
=
None
try
:
try
:
content
=
AssetManager
.
find
(
asset_key
,
as_stream
=
True
)
content
=
AssetManager
.
find
(
asset_key
,
as_stream
=
True
)
serve_from_cdn
=
not
getattr
(
content
,
"locked"
,
True
)
is_locked
=
getattr
(
content
,
"locked"
,
True
)
content_digest
=
content
.
content_digest
serve_from_cdn
=
not
is_locked
except
(
ItemNotFoundError
,
NotFoundError
):
except
(
ItemNotFoundError
,
NotFoundError
):
# If we can't find the item, just treat it as if it's locked.
# If we can't find the item, just treat it as if it's locked.
serve_from_cdn
=
False
serve_from_cdn
=
False
#
Do a generic check to see if anything about this asset disqualifies it from being CDN'd.
#
See if this is an allowed file extension to serve. Some files aren't served through the
is_excluded
=
False
# CDN in order to avoid same-origin policy/CORS-related issues.
if
StaticContent
.
is_excluded_asset_type
(
relative_path
,
excluded_exts
):
if
any
(
relative_path
.
lower
()
.
endswith
(
excluded_ext
.
lower
())
for
excluded_ext
in
excluded_exts
):
serve_from_cdn
=
False
serve_from_cdn
=
False
is_excluded
=
True
# Update any query parameter values that have asset paths in them. This is for assets that
# Update any query parameter values that have asset paths in them. This is for assets that
# require their own after-the-fact values, like a Flash file that needs the path of a config
# require their own after-the-fact values, like a Flash file that needs the path of a config
...
@@ -261,29 +215,15 @@ class StaticContent(object):
...
@@ -261,29 +215,15 @@ class StaticContent(object):
updated_query_params
=
[]
updated_query_params
=
[]
for
query_name
,
query_val
in
query_params
:
for
query_name
,
query_val
in
query_params
:
if
query_val
.
startswith
(
"/static/"
):
if
query_val
.
startswith
(
"/static/"
):
new_val
=
StaticContent
.
get_canonicalized_asset_path
(
new_val
=
StaticContent
.
get_canonicalized_asset_path
(
course_key
,
query_val
,
base_url
,
excluded_exts
)
course_key
,
query_val
,
base_url
,
excluded_exts
,
encode
=
False
)
updated_query_params
.
append
((
query_name
,
new_val
))
updated_query_params
.
append
((
query_name
,
new_val
))
else
:
else
:
# Make sure we're encoding Unicode strings down to their byte string
updated_query_params
.
append
((
query_name
,
query_val
))
# representation so that `urlencode` can handle it.
updated_query_params
.
append
((
query_name
,
query_val
.
encode
(
'utf-8'
)))
serialized_asset_key
=
StaticContent
.
serialize_asset_key_with_slash
(
asset_key
)
serialized_asset_key
=
StaticContent
.
serialize_asset_key_with_slash
(
asset_key
)
base_url
=
base_url
if
serve_from_cdn
else
''
base_url
=
base_url
if
serve_from_cdn
else
''
asset_path
=
serialized_asset_key
# If the content has a digest (i.e. md5sum) value specified, create a versioned path to the asset using it.
if
not
is_excluded
and
content_digest
:
asset_path
=
StaticContent
.
add_version_to_asset_path
(
serialized_asset_key
,
content_digest
)
# Only encode this if told to. Important so that we don't double encode
# when working with paths that are in query parameters.
asset_path
=
asset_path
.
encode
(
'utf-8'
)
if
encode
:
asset_path
=
quote_plus
(
asset_path
,
'/:+@'
)
return
urlunparse
((
None
,
base_url
.
encode
(
'utf-8'
),
asset_path
,
params
,
urlencode
(
updated_query_params
),
None
))
return
urlunparse
((
None
,
base_url
,
serialized_asset_key
,
params
,
urlencode
(
updated_query_params
),
fragment
))
def
stream_data
(
self
):
def
stream_data
(
self
):
yield
self
.
_data
yield
self
.
_data
...
@@ -302,10 +242,10 @@ class StaticContent(object):
...
@@ -302,10 +242,10 @@ class StaticContent(object):
class
StaticContentStream
(
StaticContent
):
class
StaticContentStream
(
StaticContent
):
def
__init__
(
self
,
loc
,
name
,
content_type
,
stream
,
last_modified_at
=
None
,
thumbnail_location
=
None
,
import_path
=
None
,
def
__init__
(
self
,
loc
,
name
,
content_type
,
stream
,
last_modified_at
=
None
,
thumbnail_location
=
None
,
import_path
=
None
,
length
=
None
,
locked
=
False
,
content_digest
=
None
):
length
=
None
,
locked
=
False
):
super
(
StaticContentStream
,
self
)
.
__init__
(
loc
,
name
,
content_type
,
None
,
last_modified_at
=
last_modified_at
,
super
(
StaticContentStream
,
self
)
.
__init__
(
loc
,
name
,
content_type
,
None
,
last_modified_at
=
last_modified_at
,
thumbnail_location
=
thumbnail_location
,
import_path
=
import_path
,
thumbnail_location
=
thumbnail_location
,
import_path
=
import_path
,
length
=
length
,
locked
=
locked
,
content_digest
=
content_digest
)
length
=
length
,
locked
=
locked
)
self
.
_stream
=
stream
self
.
_stream
=
stream
def
stream_data
(
self
):
def
stream_data
(
self
):
...
@@ -337,8 +277,7 @@ class StaticContentStream(StaticContent):
...
@@ -337,8 +277,7 @@ class StaticContentStream(StaticContent):
self
.
_stream
.
seek
(
0
)
self
.
_stream
.
seek
(
0
)
content
=
StaticContent
(
self
.
location
,
self
.
name
,
self
.
content_type
,
self
.
_stream
.
read
(),
content
=
StaticContent
(
self
.
location
,
self
.
name
,
self
.
content_type
,
self
.
_stream
.
read
(),
last_modified_at
=
self
.
last_modified_at
,
thumbnail_location
=
self
.
thumbnail_location
,
last_modified_at
=
self
.
last_modified_at
,
thumbnail_location
=
self
.
thumbnail_location
,
import_path
=
self
.
import_path
,
length
=
self
.
length
,
locked
=
self
.
locked
,
import_path
=
self
.
import_path
,
length
=
self
.
length
,
locked
=
self
.
locked
)
content_digest
=
self
.
content_digest
)
return
content
return
content
...
...
common/lib/xmodule/xmodule/contentstore/mongo.py
View file @
2c41d79c
...
@@ -128,8 +128,7 @@ class MongoContentStore(ContentStore):
...
@@ -128,8 +128,7 @@ class MongoContentStore(ContentStore):
location
,
fp
.
displayname
,
fp
.
content_type
,
fp
,
last_modified_at
=
fp
.
uploadDate
,
location
,
fp
.
displayname
,
fp
.
content_type
,
fp
,
last_modified_at
=
fp
.
uploadDate
,
thumbnail_location
=
thumbnail_location
,
thumbnail_location
=
thumbnail_location
,
import_path
=
getattr
(
fp
,
'import_path'
,
None
),
import_path
=
getattr
(
fp
,
'import_path'
,
None
),
length
=
fp
.
length
,
locked
=
getattr
(
fp
,
'locked'
,
False
),
length
=
fp
.
length
,
locked
=
getattr
(
fp
,
'locked'
,
False
)
content_digest
=
getattr
(
fp
,
'md5'
,
None
),
)
)
else
:
else
:
with
self
.
fs
.
get
(
content_id
)
as
fp
:
with
self
.
fs
.
get
(
content_id
)
as
fp
:
...
@@ -143,8 +142,7 @@ class MongoContentStore(ContentStore):
...
@@ -143,8 +142,7 @@ class MongoContentStore(ContentStore):
location
,
fp
.
displayname
,
fp
.
content_type
,
fp
.
read
(),
last_modified_at
=
fp
.
uploadDate
,
location
,
fp
.
displayname
,
fp
.
content_type
,
fp
.
read
(),
last_modified_at
=
fp
.
uploadDate
,
thumbnail_location
=
thumbnail_location
,
thumbnail_location
=
thumbnail_location
,
import_path
=
getattr
(
fp
,
'import_path'
,
None
),
import_path
=
getattr
(
fp
,
'import_path'
,
None
),
length
=
fp
.
length
,
locked
=
getattr
(
fp
,
'locked'
,
False
),
length
=
fp
.
length
,
locked
=
getattr
(
fp
,
'locked'
,
False
)
content_digest
=
getattr
(
fp
,
'md5'
,
None
),
)
)
except
NoFile
:
except
NoFile
:
if
throw_on_not_found
:
if
throw_on_not_found
:
...
...
common/test/data/toy/static/sample_static.
html
→
common/test/data/toy/static/sample_static.
txt
View file @
2c41d79c
File moved
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