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
66f41e1d
Commit
66f41e1d
authored
Dec 02, 2014
by
Akiva Leffert
Committed by
christopher lee
Dec 03, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make static URLs absolute in handouts, updates, and about for mobile API
JIRA: MA-147
parent
b89113e1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
203 additions
and
32 deletions
+203
-32
common/djangoapps/static_replace/__init__.py
+49
-14
common/djangoapps/static_replace/test/test_static_replace.py
+38
-2
lms/djangoapps/mobile_api/course_info/tests.py
+93
-12
lms/djangoapps/mobile_api/course_info/views.py
+23
-4
No files found.
common/djangoapps/static_replace/__init__.py
View file @
66f41e1d
...
@@ -92,7 +92,50 @@ def replace_course_urls(text, course_key):
...
@@ -92,7 +92,50 @@ def replace_course_urls(text, course_key):
return
re
.
sub
(
_url_replace_regex
(
'/course/'
),
replace_course_url
,
text
)
return
re
.
sub
(
_url_replace_regex
(
'/course/'
),
replace_course_url
,
text
)
def
replace_static_urls
(
text
,
data_directory
,
course_id
=
None
,
static_asset_path
=
''
):
def
process_static_urls
(
text
,
replacement_function
,
data_dir
=
None
):
"""
Run an arbitrary replacement function on any urls matching the static file
directory
"""
def
wrap_part_extraction
(
match
):
"""
Unwraps a match group for the captures specified in _url_replace_regex
and forward them on as function arguments
"""
original
=
match
.
group
(
0
)
prefix
=
match
.
group
(
'prefix'
)
quote
=
match
.
group
(
'quote'
)
rest
=
match
.
group
(
'rest'
)
return
replacement_function
(
original
,
prefix
,
quote
,
rest
)
return
re
.
sub
(
_url_replace_regex
(
u'(?:{static_url}|/static/)(?!{data_dir})'
.
format
(
static_url
=
settings
.
STATIC_URL
,
data_dir
=
data_dir
)),
wrap_part_extraction
,
text
)
def
make_static_urls_absolute
(
request
,
html
):
"""
Converts relative URLs referencing static assets to absolute URLs
"""
def
replace
(
__
,
prefix
,
quote
,
rest
):
"""
Function to actually do a single relative -> absolute url replacement
"""
processed
=
request
.
build_absolute_uri
(
prefix
+
rest
)
return
quote
+
processed
+
quote
return
process_static_urls
(
html
,
replace
)
def
replace_static_urls
(
text
,
data_directory
=
None
,
course_id
=
None
,
static_asset_path
=
''
):
"""
"""
Replace /static/$stuff urls either with their correct url as generated by collectstatic,
Replace /static/$stuff urls either with their correct url as generated by collectstatic,
(/static/$md5_hashed_stuff) or by the course-specific content static url
(/static/$md5_hashed_stuff) or by the course-specific content static url
...
@@ -105,11 +148,10 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
...
@@ -105,11 +148,10 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
static_asset_path: Path for static assets, which overrides data_directory and course_namespace, if nonempty
static_asset_path: Path for static assets, which overrides data_directory and course_namespace, if nonempty
"""
"""
def
replace_static_url
(
match
):
def
replace_static_url
(
original
,
prefix
,
quote
,
rest
):
original
=
match
.
group
(
0
)
"""
prefix
=
match
.
group
(
'prefix'
)
Replace a single matched url.
quote
=
match
.
group
(
'quote'
)
"""
rest
=
match
.
group
(
'rest'
)
# Don't mess with things that end in '?raw'
# Don't mess with things that end in '?raw'
if
rest
.
endswith
(
'?raw'
):
if
rest
.
endswith
(
'?raw'
):
...
@@ -155,11 +197,4 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
...
@@ -155,11 +197,4 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
return
""
.
join
([
quote
,
url
,
quote
])
return
""
.
join
([
quote
,
url
,
quote
])
return
re
.
sub
(
return
process_static_urls
(
text
,
replace_static_url
,
data_dir
=
static_asset_path
or
data_directory
)
_url_replace_regex
(
u'(?:{static_url}|/static/)(?!{data_dir})'
.
format
(
static_url
=
settings
.
STATIC_URL
,
data_dir
=
static_asset_path
or
data_directory
)),
replace_static_url
,
text
)
common/djangoapps/static_replace/test/test_static_replace.py
View file @
66f41e1d
import
re
import
re
from
nose.tools
import
assert_equals
,
assert_true
,
assert_false
# pylint: disable=no-name-in-module
from
nose.tools
import
assert_equals
,
assert_true
,
assert_false
# pylint: disable=no-name-in-module
from
static_replace
import
(
replace_static_urls
,
replace_course_urls
,
from
static_replace
import
(
_url_replace_regex
)
replace_static_urls
,
replace_course_urls
,
_url_replace_regex
,
process_static_urls
,
make_static_urls_absolute
)
from
mock
import
patch
,
Mock
from
mock
import
patch
,
Mock
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
...
@@ -27,6 +32,37 @@ def test_multi_replace():
...
@@ -27,6 +32,37 @@ def test_multi_replace():
)
)
def
test_process_url
():
def
processor
(
__
,
prefix
,
quote
,
rest
):
# pylint: disable=missing-docstring
return
quote
+
'test'
+
prefix
+
rest
+
quote
assert_equals
(
'"test/static/file.png"'
,
process_static_urls
(
STATIC_SOURCE
,
processor
))
def
test_process_url_data_dir_exists
():
base
=
'"/static/{data_dir}/file.png"'
.
format
(
data_dir
=
DATA_DIRECTORY
)
def
processor
(
original
,
prefix
,
quote
,
rest
):
# pylint: disable=unused-argument,missing-docstring
return
quote
+
'test'
+
rest
+
quote
assert_equals
(
base
,
process_static_urls
(
base
,
processor
,
data_dir
=
DATA_DIRECTORY
))
def
test_process_url_no_match
():
def
processor
(
__
,
prefix
,
quote
,
rest
):
# pylint: disable=missing-docstring
return
quote
+
'test'
+
prefix
+
rest
+
quote
assert_equals
(
'"test/static/file.png"'
,
process_static_urls
(
STATIC_SOURCE
,
processor
))
@patch
(
'django.http.HttpRequest'
)
def
test_static_urls
(
mock_request
):
mock_request
.
build_absolute_uri
=
lambda
url
:
'http://'
+
url
result
=
make_static_urls_absolute
(
mock_request
,
STATIC_SOURCE
)
assert_equals
(
result
,
'
\"
http:///static/file.png
\"
'
)
@patch
(
'static_replace.staticfiles_storage'
)
@patch
(
'static_replace.staticfiles_storage'
)
def
test_storage_url_exists
(
mock_storage
):
def
test_storage_url_exists
(
mock_storage
):
mock_storage
.
exists
.
return_value
=
True
mock_storage
.
exists
.
return_value
=
True
...
...
lms/djangoapps/mobile_api/course_info/tests.py
View file @
66f41e1d
"""
"""
Tests for course_info
Tests for course_info
"""
"""
from
django.test.utils
import
override_settings
import
json
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
rest_framework.test
import
APITestCase
from
rest_framework.test
import
APITestCase
from
courseware.tests.factories
import
UserFactory
from
xmodule.html_module
import
CourseInfoModule
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
courseware.tests.factories
import
UserFactory
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
courseware.tests.tests
import
TEST_DATA_MONGO_MODULESTORE
@override_settings
(
MODULESTORE
=
TEST_DATA_MONGO_MODULESTORE
)
class
TestCourseInfo
(
APITestCase
):
class
TestVideoOutline
(
ModuleStoreTestCase
,
APITestCase
):
"""
"""
Tests for /api/mobile/v0.5/course_info/...
Tests for /api/mobile/v0.5/course_info/...
"""
"""
def
setUp
(
self
):
def
setUp
(
self
):
super
(
Test
VideoOutline
,
self
)
.
setUp
()
super
(
Test
CourseInfo
,
self
)
.
setUp
()
self
.
user
=
UserFactory
.
create
()
self
.
user
=
UserFactory
.
create
()
self
.
course
=
CourseFactory
.
create
(
mobile_available
=
True
)
self
.
course
=
CourseFactory
.
create
(
mobile_available
=
True
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
'test'
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
'test'
)
...
@@ -27,14 +31,91 @@ class TestVideoOutline(ModuleStoreTestCase, APITestCase):
...
@@ -27,14 +31,91 @@ class TestVideoOutline(ModuleStoreTestCase, APITestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertTrue
(
'overview'
in
response
.
data
)
# pylint: disable=maybe-no-member
self
.
assertTrue
(
'overview'
in
response
.
data
)
# pylint: disable=maybe-no-member
def
test_handouts
(
self
):
url
=
reverse
(
'course-handouts-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_updates
(
self
):
def
test_updates
(
self
):
url
=
reverse
(
'course-updates-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
url
=
reverse
(
'course-updates-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
data
,
[])
# pylint: disable=maybe-no-member
self
.
assertEqual
(
response
.
data
,
[])
# pylint: disable=maybe-no-member
# TODO: add handouts and updates, somehow
def
test_about_static_rewrites
(
self
):
about_usage_key
=
self
.
course
.
id
.
make_usage_key
(
'about'
,
'overview'
)
about_module
=
modulestore
()
.
get_item
(
about_usage_key
)
underlying_about_html
=
about_module
.
data
# check that we start with relative static assets
self
.
assertIn
(
'
\"
/static/'
,
underlying_about_html
)
url
=
reverse
(
'course-about-detail'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
json_data
=
json
.
loads
(
response
.
content
)
about_html
=
json_data
[
'overview'
]
# but shouldn't finish with any
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertNotIn
(
'
\"
/static/'
,
about_html
)
def
test_updates_rewrite
(
self
):
updates_usage_key
=
self
.
course
.
id
.
make_usage_key
(
'course_info'
,
'updates'
)
course_updates
=
modulestore
()
.
create_item
(
self
.
user
.
id
,
updates_usage_key
.
course_key
,
updates_usage_key
.
block_type
,
block_id
=
updates_usage_key
.
block_id
)
course_update_data
=
{
"id"
:
1
,
"date"
:
"Some date"
,
"content"
:
"<a href=
\"
/static/
\"
>foo</a>"
,
"status"
:
CourseInfoModule
.
STATUS_VISIBLE
}
course_updates
.
items
=
[
course_update_data
]
modulestore
()
.
update_item
(
course_updates
,
self
.
user
.
id
)
url
=
reverse
(
'course-updates-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
content
=
response
.
data
[
0
][
"content"
]
# pylint: disable=maybe-no-member
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertNotIn
(
"
\"
/static/"
,
content
)
underlying_updates_module
=
modulestore
()
.
get_item
(
updates_usage_key
)
self
.
assertIn
(
"
\"
/static/"
,
underlying_updates_module
.
items
[
0
][
'content'
])
class
TestHandoutInfo
(
ModuleStoreTestCase
,
APITestCase
):
"""
Tests for /api/mobile/v0.5/course_info/{course_id}/handouts
"""
def
setUp
(
self
):
super
(
TestHandoutInfo
,
self
)
.
setUp
()
self
.
user
=
UserFactory
.
create
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
'test'
)
course_items
=
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
settings
.
COMMON_TEST_DATA_ROOT
,
[
'toy'
])
self
.
course
=
course_items
[
0
]
def
test_no_handouts
(
self
):
empty_course
=
CourseFactory
.
create
(
mobile_available
=
True
)
url
=
reverse
(
'course-handouts-list'
,
kwargs
=
{
'course_id'
:
unicode
(
empty_course
.
id
)})
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_handout_exists
(
self
):
url
=
reverse
(
'course-handouts-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_handout_static_rewrites
(
self
):
# check that we start with relative static assets
handouts_usage_key
=
self
.
course
.
id
.
make_usage_key
(
'course_info'
,
'handouts'
)
underlying_handouts
=
self
.
store
.
get_item
(
handouts_usage_key
)
self
.
assertIn
(
'
\'
/static/'
,
underlying_handouts
.
data
)
url
=
reverse
(
'course-handouts-list'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
url
)
json_data
=
json
.
loads
(
response
.
content
)
handouts_html
=
json_data
[
'handouts_html'
]
# but shouldn't finish with any
self
.
assertNotIn
(
'
\'
/static/'
,
handouts_html
)
self
.
assertEqual
(
response
.
status_code
,
200
)
lms/djangoapps/mobile_api/course_info/views.py
View file @
66f41e1d
...
@@ -10,6 +10,7 @@ from courseware.courses import get_course_about_section, get_course_info_section
...
@@ -10,6 +10,7 @@ from courseware.courses import get_course_about_section, get_course_info_section
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.keys
import
CourseKey
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
static_replace
import
make_static_urls_absolute
,
replace_static_urls
class
CourseUpdatesList
(
generics
.
ListAPIView
):
class
CourseUpdatesList
(
generics
.
ListAPIView
):
...
@@ -28,8 +29,7 @@ class CourseUpdatesList(generics.ListAPIView):
...
@@ -28,8 +29,7 @@ class CourseUpdatesList(generics.ListAPIView):
* date: The date of the course update.
* date: The date of the course update.
* content: The content, as a string, of the course update. HTML tags
* content: The content, as an HTML string, of the course update.
are not included in the string.
* status: Whether the update is visible or not.
* status: Whether the update is visible or not.
...
@@ -42,10 +42,21 @@ class CourseUpdatesList(generics.ListAPIView):
...
@@ -42,10 +42,21 @@ class CourseUpdatesList(generics.ListAPIView):
course_id
=
CourseKey
.
from_string
(
kwargs
[
'course_id'
])
course_id
=
CourseKey
.
from_string
(
kwargs
[
'course_id'
])
course
=
modulestore
()
.
get_course
(
course_id
)
course
=
modulestore
()
.
get_course
(
course_id
)
course_updates_module
=
get_course_info_section_module
(
request
,
course
,
'updates'
)
course_updates_module
=
get_course_info_section_module
(
request
,
course
,
'updates'
)
update_items
=
reversed
(
getattr
(
course_updates_module
,
'items'
,
[]))
updates_to_show
=
[
updates_to_show
=
[
update
for
update
in
reversed
(
getattr
(
course_updates_module
,
'items'
,
[]))
update
for
update
in
update_items
if
update
.
get
(
"status"
)
!=
"deleted"
if
update
.
get
(
"status"
)
!=
"deleted"
]
]
for
item
in
updates_to_show
:
content
=
item
[
'content'
]
content
=
replace_static_urls
(
content
,
course_id
=
course_id
,
static_asset_path
=
course
.
static_asset_path
)
item
[
'content'
]
=
make_static_urls_absolute
(
request
,
content
)
return
Response
(
updates_to_show
)
return
Response
(
updates_to_show
)
...
@@ -71,7 +82,13 @@ class CourseHandoutsList(generics.ListAPIView):
...
@@ -71,7 +82,13 @@ class CourseHandoutsList(generics.ListAPIView):
course
=
modulestore
()
.
get_course
(
course_id
)
course
=
modulestore
()
.
get_course
(
course_id
)
course_handouts_module
=
get_course_info_section_module
(
request
,
course
,
'handouts'
)
course_handouts_module
=
get_course_info_section_module
(
request
,
course
,
'handouts'
)
if
course_handouts_module
:
if
course_handouts_module
:
return
Response
({
'handouts_html'
:
course_handouts_module
.
data
})
handouts_html
=
course_handouts_module
.
data
handouts_html
=
replace_static_urls
(
handouts_html
,
course_id
=
course_id
,
static_asset_path
=
course
.
static_asset_path
)
handouts_html
=
make_static_urls_absolute
(
self
.
request
,
handouts_html
)
return
Response
({
'handouts_html'
:
handouts_html
})
else
:
else
:
# course_handouts_module could be None if there are no handouts
# course_handouts_module could be None if there are no handouts
# (such as while running tests)
# (such as while running tests)
...
@@ -104,6 +121,8 @@ class CourseAboutDetail(generics.RetrieveAPIView):
...
@@ -104,6 +121,8 @@ class CourseAboutDetail(generics.RetrieveAPIView):
#
#
# This can also return None, so check for that before calling strip()
# This can also return None, so check for that before calling strip()
about_section_html
=
get_course_about_section
(
course
,
"overview"
)
about_section_html
=
get_course_about_section
(
course
,
"overview"
)
about_section_html
=
make_static_urls_absolute
(
self
.
request
,
about_section_html
)
return
Response
(
return
Response
(
{
"overview"
:
about_section_html
.
strip
()
if
about_section_html
else
""
}
{
"overview"
:
about_section_html
.
strip
()
if
about_section_html
else
""
}
)
)
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