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
1c882da3
Commit
1c882da3
authored
Jun 30, 2014
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make Studio able to handle deprecated key formats in urls
parent
cb3355b9
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
97 additions
and
82 deletions
+97
-82
cms/djangoapps/contentstore/tests/test_contentstore.py
+1
-32
cms/djangoapps/contentstore/tests/test_import.py
+1
-1
cms/djangoapps/contentstore/views/component.py
+7
-7
cms/djangoapps/contentstore/views/item.py
+14
-14
cms/djangoapps/contentstore/views/tests/test_course_index.py
+2
-1
cms/djangoapps/contentstore/views/tests/test_item.py
+4
-1
cms/urls.py
+26
-22
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+42
-4
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
1c882da3
...
...
@@ -131,7 +131,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
descriptor
=
store
.
get_items
(
course
.
id
,
category
=
'vertical'
,)
resp
=
self
.
client
.
get_html
(
get_url
(
'unit_handler'
,
descriptor
[
0
]
.
location
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
_test_no_locations
(
self
,
resp
)
for
expected
in
expected_types
:
self
.
assertIn
(
expected
,
resp
.
content
)
...
...
@@ -157,7 +156,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
resp
=
self
.
client
.
get_html
(
get_url
(
'unit_handler'
,
usage_key
))
self
.
assertEqual
(
resp
.
status_code
,
400
)
_test_no_locations
(
self
,
resp
,
status_code
=
400
)
def
check_edit_unit
(
self
,
test_course_name
):
_
,
course_items
=
import_from_xml
(
modulestore
(),
self
.
user
.
id
,
'common/test/data/'
,
[
test_course_name
])
...
...
@@ -364,8 +362,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
get_url
(
'xblock_view_handler'
,
usage_key
,
kwargs
=
{
'view_name'
:
'container_preview'
})
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# TODO: uncomment when preview no longer has locations being returned.
# _test_no_locations(self, resp)
# These are the data-ids of the xblocks contained in the vertical.
self
.
assertContains
(
resp
,
'edX+toy+2012_Fall+video+sample_video'
)
...
...
@@ -534,7 +530,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
url
=
reverse_course_url
(
'assets_handler'
,
course
.
id
,
kwargs
=
{
'asset_key_string'
:
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.txt'
)}
kwargs
=
{
'asset_key_string'
:
unicode
(
course
.
id
.
make_asset_key
(
'asset'
,
'sample_static.txt'
)
)}
)
resp
=
self
.
client
.
delete
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
...
...
@@ -761,7 +757,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
def
test_bad_contentstore_request
(
self
):
resp
=
self
.
client
.
get_html
(
'http://localhost:8001/c4x/CDX/123123/asset/&images_circuits_Lab7Solution2.png'
)
self
.
assertEqual
(
resp
.
status_code
,
400
)
_test_no_locations
(
self
,
resp
,
400
)
def
test_rewrite_nonportable_links_on_import
(
self
):
module_store
=
modulestore
()
...
...
@@ -1196,7 +1191,6 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
for
descriptor
in
items
:
resp
=
self
.
client
.
get_html
(
get_url
(
'unit_handler'
,
descriptor
.
location
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
_test_no_locations
(
self
,
resp
)
class
ContentStoreTest
(
ContentStoreTestCase
):
...
...
@@ -1475,7 +1469,6 @@ class ContentStoreTest(ContentStoreTestCase):
status_code
=
200
,
html
=
True
)
_test_no_locations
(
self
,
resp
)
def
test_course_factory
(
self
):
"""Test that the course factory works correctly."""
...
...
@@ -1498,7 +1491,6 @@ class ContentStoreTest(ContentStoreTestCase):
status_code
=
200
,
html
=
True
)
_test_no_locations
(
self
,
resp
)
def
test_course_overview_view_with_course
(
self
):
"""Test viewing the course overview page with an existing course"""
...
...
@@ -1522,7 +1514,6 @@ class ContentStoreTest(ContentStoreTestCase):
}
resp
=
self
.
client
.
ajax_post
(
reverse_url
(
'xblock_handler'
),
section_data
)
_test_no_locations
(
self
,
resp
,
html
=
False
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
data
=
parse_json
(
resp
)
...
...
@@ -1563,7 +1554,6 @@ class ContentStoreTest(ContentStoreTestCase):
get_url
(
handler
,
course_key
,
'course_key_string'
)
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
_test_no_locations
(
self
,
resp
)
_
,
course_items
=
import_from_xml
(
modulestore
(),
self
.
user
.
id
,
'common/test/data/'
,
[
'simple'
])
course_key
=
course_items
[
0
]
.
id
...
...
@@ -1589,20 +1579,17 @@ class ContentStoreTest(ContentStoreTestCase):
subsection_key
=
course_key
.
make_usage_key
(
'sequential'
,
'test_sequence'
)
resp
=
self
.
client
.
get_html
(
get_url
(
'subsection_handler'
,
subsection_key
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
_test_no_locations
(
self
,
resp
)
# go look at the Edit page
unit_key
=
course_key
.
make_usage_key
(
'vertical'
,
'test_vertical'
)
resp
=
self
.
client
.
get_html
(
get_url
(
'unit_handler'
,
unit_key
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
_test_no_locations
(
self
,
resp
)
def
delete_item
(
category
,
name
):
""" Helper method for testing the deletion of an xblock item. """
item_key
=
course_key
.
make_usage_key
(
category
,
name
)
resp
=
self
.
client
.
delete
(
get_url
(
'xblock_handler'
,
item_key
))
self
.
assertEqual
(
resp
.
status_code
,
204
)
_test_no_locations
(
self
,
resp
,
status_code
=
204
,
html
=
False
)
# delete a component
delete_item
(
category
=
'html'
,
name
=
'test_html'
)
...
...
@@ -1805,7 +1792,6 @@ class ContentStoreTest(ContentStoreTestCase):
Show the course overview page.
"""
resp
=
self
.
client
.
get_html
(
get_url
(
'course_handler'
,
course_key
,
'course_key_string'
))
_test_no_locations
(
self
,
resp
)
return
resp
def
test_wiki_slug
(
self
):
...
...
@@ -1887,7 +1873,6 @@ class EntryPageTestCase(TestCase):
def
_test_page
(
self
,
page
,
status_code
=
200
):
resp
=
self
.
client
.
get_html
(
page
)
self
.
assertEqual
(
resp
.
status_code
,
status_code
)
_test_no_locations
(
self
,
resp
,
status_code
)
def
test_how_it_works
(
self
):
self
.
_test_page
(
"/howitworks"
)
...
...
@@ -1925,19 +1910,3 @@ def _course_factory_create_course():
def
_get_course_id
(
course_data
):
"""Returns the course ID (org/number/run)."""
return
SlashSeparatedCourseKey
(
course_data
[
'org'
],
course_data
[
'number'
],
course_data
[
'run'
])
def
_test_no_locations
(
test
,
resp
,
status_code
=
200
,
html
=
True
):
"""
Verifies that "i4x", which appears in old locations, but not
new locators, does not appear in the HTML response output.
Used to verify that database refactoring is complete.
"""
test
.
assertNotContains
(
resp
,
'i4x'
,
status_code
=
status_code
,
html
=
html
)
if
html
:
# For HTML pages, it is nice to call the method with html=True because
# it checks that the HTML properly parses. However, it won't find i4x usages
# in JavaScript blocks.
content
=
resp
.
content
hits
=
len
(
re
.
findall
(
r"(?<!jump_to/)i4x://"
,
content
))
test
.
assertEqual
(
hits
,
0
,
"i4x found outside of LMS jump-to links"
)
cms/djangoapps/contentstore/tests/test_import.py
View file @
1c882da3
...
...
@@ -189,7 +189,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
target_course_id
.
make_usage_key
(
'conditional'
,
'condone'
)
)
self
.
assertIsNotNone
(
conditional_module
)
different_course_id
=
SlashSeparatedCourseKey
(
'edX'
,
'different_course'
,
'copy_run'
)
different_course_id
=
SlashSeparatedCourseKey
(
'edX'
,
'different_course'
,
None
)
self
.
assertListEqual
(
[
target_course_id
.
make_usage_key
(
'problem'
,
'choiceprob'
),
...
...
cms/djangoapps/contentstore/views/component.py
View file @
1c882da3
...
...
@@ -61,7 +61,7 @@ else:
# XBlocks from pmitros repos are prototypes. They should not be used
# except for edX Learning Sciences experiments on edge.edx.org without
# further work to make them robust, maintainable, finalize data formats,
# etc.
# etc.
'concept'
,
# Concept mapper. See https://github.com/pmitros/ConceptXBlock
'done'
,
# Lets students mark things as done. See https://github.com/pmitros/DoneXBlock
'audio'
,
# Embed an audio file. See https://github.com/pmitros/AudioXBlock
...
...
@@ -97,7 +97,7 @@ def subsection_handler(request, usage_key_string):
except
ItemNotFoundError
:
return
HttpResponseBadRequest
()
preview_link
=
get_lms_link_for_item
(
usage_key
,
preview
=
True
)
preview_link
=
get_lms_link_for_item
(
item
.
location
,
preview
=
True
)
# make sure that location references a 'sequential', otherwise return
# BadRequest
...
...
@@ -134,9 +134,9 @@ def subsection_handler(request, usage_key_string):
'new_unit_category'
:
'vertical'
,
'lms_link'
:
lms_link
,
'preview_link'
:
preview_link
,
'course_graders'
:
json
.
dumps
(
CourseGradingModel
.
fetch
(
usage_key
.
course_key
)
.
graders
),
'course_graders'
:
json
.
dumps
(
CourseGradingModel
.
fetch
(
item
.
location
.
course_key
)
.
graders
),
'parent_item'
:
parent
,
'locator'
:
usage_key
,
'locator'
:
item
.
location
,
'policy_metadata'
:
policy_metadata
,
'subsection_units'
:
subsection_units
,
'can_view_live'
:
can_view_live
...
...
@@ -211,7 +211,7 @@ def unit_handler(request, usage_key_string):
return
render_to_response
(
'unit.html'
,
{
'context_course'
:
course
,
'unit'
:
item
,
'unit_usage_key'
:
usage_key
,
'unit_usage_key'
:
item
.
location
,
'child_usage_keys'
:
[
block
.
scope_ids
.
usage_id
for
block
in
xblocks
],
'component_templates'
:
json
.
dumps
(
component_templates
),
'draft_preview_link'
:
preview_lms_link
,
...
...
@@ -267,7 +267,7 @@ def container_handler(request, usage_key_string):
'context_course'
:
course
,
# Needed only for display of menus at top of page.
'xblock'
:
xblock
,
'unit_publish_state'
:
unit_publish_state
,
'xblock_locator'
:
usage_key
,
'xblock_locator'
:
xblock
.
location
,
'unit'
:
None
if
not
ancestor_xblocks
else
ancestor_xblocks
[
0
],
'ancestor_xblocks'
:
ancestor_xblocks
,
'component_templates'
:
json
.
dumps
(
component_templates
),
...
...
@@ -415,7 +415,7 @@ def _get_item_in_course(request, usage_key):
course
=
modulestore
()
.
get_course
(
course_key
)
item
=
modulestore
()
.
get_item
(
usage_key
,
depth
=
1
)
lms_link
=
get_lms_link_for_item
(
usage_key
)
lms_link
=
get_lms_link_for_item
(
item
.
location
)
return
course
,
item
,
lms_link
...
...
cms/djangoapps/contentstore/views/item.py
View file @
1c882da3
...
...
@@ -144,7 +144,7 @@ def xblock_handler(request, usage_key_string):
request
.
user
,
)
return
JsonResponse
({
"locator"
:
unicode
(
dest_usage_key
)})
return
JsonResponse
({
"locator"
:
unicode
(
dest_usage_key
)
,
"courseKey"
:
unicode
(
dest_usage_key
.
course_key
)
})
else
:
return
_create_item
(
request
)
else
:
...
...
@@ -403,7 +403,7 @@ def _create_item(request):
if
display_name
is
not
None
:
metadata
[
'display_name'
]
=
display_name
store
.
create_and_save_xmodule
(
created_block
=
store
.
create_and_save_xmodule
(
dest_usage_key
,
request
.
user
.
id
,
definition_data
=
data
,
...
...
@@ -426,10 +426,10 @@ def _create_item(request):
# TODO replace w/ nicer accessor
if
not
'detached'
in
parent
.
runtime
.
load_block_type
(
category
)
.
_class_tags
:
parent
.
children
.
append
(
dest_usage_key
)
parent
.
children
.
append
(
created_block
.
location
)
store
.
update_item
(
parent
,
request
.
user
.
id
)
return
JsonResponse
({
"locator"
:
unicode
(
dest_usage_key
),
"courseKey"
:
unicode
(
dest_usage_key
.
course_key
)})
return
JsonResponse
({
"locator"
:
unicode
(
created_block
.
location
),
"courseKey"
:
unicode
(
created_block
.
location
.
course_key
)})
def
_duplicate_item
(
parent_usage_key
,
duplicate_source_usage_key
,
display_name
=
None
,
user
=
None
):
...
...
@@ -439,8 +439,8 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
store
=
modulestore
()
source_item
=
store
.
get_item
(
duplicate_source_usage_key
)
# Change the blockID to be unique.
dest_usage_key
=
duplicate_source_usage_key
.
replace
(
name
=
uuid4
()
.
hex
)
category
=
dest_usage_key
.
category
dest_usage_key
=
source_item
.
location
.
replace
(
name
=
uuid4
()
.
hex
)
category
=
dest_usage_key
.
block_type
# Update the display name to indicate this is a duplicate (unless display name provided).
duplicate_metadata
=
own_metadata
(
source_item
)
...
...
@@ -465,7 +465,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
if
source_item
.
has_children
:
dest_module
.
children
=
[]
for
child
in
source_item
.
children
:
dupe
=
_duplicate_item
(
dest_
usage_key
,
child
,
user
=
user
)
dupe
=
_duplicate_item
(
dest_
module
.
location
,
child
,
user
=
user
)
dest_module
.
children
.
append
(
dupe
)
store
.
update_item
(
dest_module
,
user
.
id
if
user
else
None
)
...
...
@@ -473,14 +473,14 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
parent
=
store
.
get_item
(
parent_usage_key
)
# If source was already a child of the parent, add duplicate immediately afterward.
# Otherwise, add child to end.
if
duplicate_source_usage_key
in
parent
.
children
:
source_index
=
parent
.
children
.
index
(
duplicate_source_usage_key
)
parent
.
children
.
insert
(
source_index
+
1
,
dest_
usage_key
)
if
source_item
.
location
in
parent
.
children
:
source_index
=
parent
.
children
.
index
(
source_item
.
location
)
parent
.
children
.
insert
(
source_index
+
1
,
dest_
module
.
location
)
else
:
parent
.
children
.
append
(
dest_
usage_key
)
parent
.
children
.
append
(
dest_
module
.
location
)
store
.
update_item
(
parent
,
user
.
id
if
user
else
None
)
return
dest_
usage_key
return
dest_
module
.
location
def
_delete_item
(
usage_key
,
user
):
...
...
@@ -553,12 +553,12 @@ def _get_module_info(usage_key, user, rewrite_static_links=True):
data
=
replace_static_urls
(
data
,
None
,
course_id
=
usage_key
.
course_key
course_id
=
module
.
location
.
course_key
)
# Note that children aren't being returned until we have a use case.
return
{
'id'
:
unicode
(
usage_key
),
'id'
:
unicode
(
module
.
location
),
'data'
:
data
,
'metadata'
:
own_metadata
(
module
)
}
cms/djangoapps/contentstore/views/tests/test_course_index.py
View file @
1c882da3
...
...
@@ -4,6 +4,7 @@ Unit tests for getting the list of courses and the course outline.
import
json
import
lxml
from
cms.urls
import
COURSE_KEY_PATTERN
from
contentstore.tests.utils
import
CourseTestCase
from
contentstore.utils
import
reverse_course_url
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
...
...
@@ -38,7 +39,7 @@ class TestCourseIndex(CourseTestCase):
for
link
in
course_link_eles
:
self
.
assertRegexpMatches
(
link
.
get
(
"href"
),
'course/
slashes:{0}'
.
format
(
Locator
.
ALLOWED_ID_CHARS
)
'course/
{}'
.
format
(
COURSE_KEY_PATTERN
)
)
# now test that url
outline_response
=
authed_client
.
get
(
link
.
get
(
"href"
),
{},
HTTP_ACCEPT
=
'text/html'
)
...
...
cms/djangoapps/contentstore/views/tests/test_item.py
View file @
1c882da3
...
...
@@ -53,7 +53,10 @@ class ItemTest(CourseTestCase):
"""
parsed
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response
.
status_code
,
200
)
return
UsageKey
.
from_string
(
parsed
[
'locator'
])
key
=
UsageKey
.
from_string
(
parsed
[
'locator'
])
if
key
.
course_key
.
run
is
None
:
key
=
key
.
map_into_course
(
CourseKey
.
from_string
(
parsed
[
'courseKey'
]))
return
key
def
create_xblock
(
self
,
parent_usage_key
=
None
,
display_name
=
None
,
category
=
None
,
boilerplate
=
None
):
data
=
{
...
...
cms/urls.py
View file @
1c882da3
...
...
@@ -5,6 +5,10 @@ from django.conf.urls import patterns, include, url
from
ratelimitbackend
import
admin
admin
.
autodiscover
()
COURSE_KEY_PATTERN
=
r'(?P<course_key_string>(?:[^/]+/[^/]+/[^/]+)|(?:[^/]+))'
USAGE_KEY_PATTERN
=
r'(?P<usage_key_string>(?:i4x://?[^/]+/[^/]+/[^/]+/[^@]+(?:@[^/]+)?)|(?:[^/]+))'
ASSET_KEY_PATTERN
=
r'(?P<asset_key_string>(?:/?c4x(:/)?/[^/]+/[^/]+/[^/]+/[^@]+(?:@[^/]+)?)|(?:[^/]+))'
urlpatterns
=
patterns
(
''
,
# nopep8
url
(
r'^transcripts/upload$'
,
'contentstore.views.upload_transcripts'
,
name
=
'upload_transcripts'
),
...
...
@@ -66,30 +70,30 @@ urlpatterns += patterns(
url
(
r'^signin$'
,
'login_page'
,
name
=
'login'
),
url
(
r'^request_course_creator$'
,
'request_course_creator'
),
url
(
r'^course_team/
(?P<course_key_string>[^/]+)/(?P<email>.+)?$'
,
'course_team_handler'
),
url
(
r'^course_info/
(?P<course_key_string>[^/]+)$'
,
'course_info_handler'
),
url
(
r'^course_team/
{}/(?P<email>.+)?$'
.
format
(
COURSE_KEY_PATTERN
)
,
'course_team_handler'
),
url
(
r'^course_info/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'course_info_handler'
),
url
(
r'^course_info_update/
(?P<course_key_string>[^/]+)/(?P<provided_id>\d+)?$'
,
r'^course_info_update/
{}/(?P<provided_id>\d+)?$'
.
format
(
COURSE_KEY_PATTERN
)
,
'course_info_update_handler'
),
url
(
r'^course/
(?P<course_key_string>[^/]+)?$'
,
'course_handler'
,
name
=
'course_handler'
),
url
(
r'^subsection/
(?P<usage_key_string>[^/]+)$'
,
'subsection_handler'
),
url
(
r'^unit/
(?P<usage_key_string>[^/]+)$'
,
'unit_handler'
),
url
(
r'^container/
(?P<usage_key_string>[^/]+)$'
,
'container_handler'
),
url
(
r'^checklists/
(?P<course_key_string>[^/]+)/(?P<checklist_index>\d+)?$'
,
'checklists_handler'
),
url
(
r'^orphan/
(?P<course_key_string>[^/]+)$'
,
'orphan_handler'
),
url
(
r'^assets/
(?P<course_key_string>[^/]+)/(?P<asset_key_string>.+)?$'
,
'assets_handler'
),
url
(
r'^import/
(?P<course_key_string>[^/]+)$'
,
'import_handler'
),
url
(
r'^import_status/
(?P<course_key_string>[^/]+)/(?P<filename>.+)$'
,
'import_status_handler'
),
url
(
r'^export/
(?P<course_key_string>[^/]+)$'
,
'export_handler'
),
url
(
r'^xblock/
(?P<usage_key_string>[^/]+)/(?P<view_name>[^/]+)$'
,
'xblock_view_handler'
),
url
(
r'^xblock/
(?P<usage_key_string>[^/]+)?$'
,
'xblock_handler'
),
url
(
r'^tabs/
(?P<course_key_string>[^/]+)$'
,
'tabs_handler'
),
url
(
r'^settings/details/
(?P<course_key_string>[^/]+)$'
,
'settings_handler'
),
url
(
r'^settings/grading/
(?P<course_key_string>[^/]+)(/)?(?P<grader_index>\d+)?$'
,
'grading_handler'
),
url
(
r'^settings/advanced/
(?P<course_key_string>[^/]+)$'
,
'advanced_settings_handler'
),
url
(
r'^textbooks/
(?P<course_key_string>[^/]+)$'
,
'textbooks_list_handler'
),
url
(
r'^textbooks/
(?P<course_key_string>[^/]+)/(?P<textbook_id>\d[^/]*)$'
,
'textbooks_detail_handler'
),
url
(
r'^course/
{}?$'
.
format
(
COURSE_KEY_PATTERN
)
,
'course_handler'
,
name
=
'course_handler'
),
url
(
r'^subsection/
{}$'
.
format
(
USAGE_KEY_PATTERN
)
,
'subsection_handler'
),
url
(
r'^unit/
{}$'
.
format
(
USAGE_KEY_PATTERN
)
,
'unit_handler'
),
url
(
r'^container/
{}$'
.
format
(
USAGE_KEY_PATTERN
)
,
'container_handler'
),
url
(
r'^checklists/
{}/(?P<checklist_index>\d+)?$'
.
format
(
COURSE_KEY_PATTERN
)
,
'checklists_handler'
),
url
(
r'^orphan/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'orphan_handler'
),
url
(
r'^assets/
{}/{}?$'
.
format
(
COURSE_KEY_PATTERN
,
ASSET_KEY_PATTERN
)
,
'assets_handler'
),
url
(
r'^import/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'import_handler'
),
url
(
r'^import_status/
{}/(?P<filename>.+)$'
.
format
(
COURSE_KEY_PATTERN
)
,
'import_status_handler'
),
url
(
r'^export/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'export_handler'
),
url
(
r'^xblock/
{}/(?P<view_name>[^/]+)$'
.
format
(
USAGE_KEY_PATTERN
)
,
'xblock_view_handler'
),
url
(
r'^xblock/
{}?$'
.
format
(
USAGE_KEY_PATTERN
)
,
'xblock_handler'
),
url
(
r'^tabs/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'tabs_handler'
),
url
(
r'^settings/details/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'settings_handler'
),
url
(
r'^settings/grading/
{}(/)?(?P<grader_index>\d+)?$'
.
format
(
COURSE_KEY_PATTERN
)
,
'grading_handler'
),
url
(
r'^settings/advanced/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'advanced_settings_handler'
),
url
(
r'^textbooks/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'textbooks_list_handler'
),
url
(
r'^textbooks/
{}/(?P<textbook_id>\d[^/]*)$'
.
format
(
COURSE_KEY_PATTERN
)
,
'textbooks_detail_handler'
),
)
js_info_dict
=
{
...
...
@@ -105,7 +109,7 @@ urlpatterns += patterns('',
if
settings
.
FEATURES
.
get
(
'ENABLE_EXPORT_GIT'
):
urlpatterns
+=
(
url
(
r'^export_git/
(?P<course_key_string>[^/]+)$'
,
urlpatterns
+=
(
url
(
r'^export_git/
{}$'
.
format
(
COURSE_KEY_PATTERN
)
,
'contentstore.views.export_git'
,
name
=
'export_git'
),)
if
settings
.
FEATURES
.
get
(
'ENABLE_SERVICE_STATUS'
):
...
...
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
1c882da3
...
...
@@ -197,7 +197,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
del
metadata
[
old_name
]
children
=
[
location
.
course_key
.
make_usage_key_from_deprecated_string
(
childloc
)
self
.
_convert_reference_to_key
(
childloc
)
for
childloc
in
definition
.
get
(
'children'
,
[])
]
data
=
definition
.
get
(
'data'
,
{})
...
...
@@ -254,6 +254,13 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
error_msg
=
exc_info_to_str
(
sys
.
exc_info
())
)
def
_convert_reference_to_key
(
self
,
ref_string
):
"""
Convert a single serialized UsageKey string in a ReferenceField into a UsageKey.
"""
key
=
Location
.
from_deprecated_string
(
ref_string
)
return
key
.
replace
(
run
=
self
.
modulestore
.
_fill_in_run
(
key
.
course_key
)
.
run
)
def
_convert_reference_fields_to_keys
(
self
,
class_
,
course_key
,
jsonfields
):
"""
Find all fields of type reference and convert the payload into UsageKeys
...
...
@@ -267,15 +274,15 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
if
field
is
None
:
continue
elif
isinstance
(
field
,
Reference
):
jsonfields
[
field_name
]
=
course_key
.
make_usage_key_from_deprecated_string
(
value
)
jsonfields
[
field_name
]
=
self
.
_convert_reference_to_key
(
value
)
elif
isinstance
(
field
,
ReferenceList
):
jsonfields
[
field_name
]
=
[
course_key
.
make_usage_key_from_deprecated_string
(
ele
)
for
ele
in
value
self
.
_convert_reference_to_key
(
ele
)
for
ele
in
value
]
elif
isinstance
(
field
,
ReferenceValueDict
):
for
key
,
subvalue
in
value
.
iteritems
():
assert
isinstance
(
subvalue
,
basestring
)
value
[
key
]
=
course_key
.
make_usage_key_from_deprecated_string
(
subvalue
)
value
[
key
]
=
self
.
_convert_reference_to_key
(
subvalue
)
return
jsonfields
...
...
@@ -378,6 +385,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
# performance optimization to prevent updating the meta-data inheritance tree during
# bulk write operations
self
.
ignore_write_events_on_courses
=
set
()
self
.
_course_run_cache
=
{}
def
begin_bulk_write_operation_on_course
(
self
,
course_id
):
"""
...
...
@@ -394,6 +402,27 @@ class MongoModuleStore(ModuleStoreWriteBase):
self
.
ignore_write_events_on_courses
.
remove
(
course_id
)
self
.
refresh_cached_metadata_inheritance_tree
(
course_id
)
def
_fill_in_run
(
self
,
course_key
):
if
course_key
.
run
is
not
None
:
return
course_key
cache_key
=
(
course_key
.
org
,
course_key
.
course
)
if
cache_key
not
in
self
.
_course_run_cache
:
matching_courses
=
list
(
self
.
collection
.
find
(
SON
([
(
'_id.tag'
,
'i4x'
),
(
'_id.org'
,
course_key
.
org
),
(
'_id.course'
,
course_key
.
course
),
(
'_id.category'
,
'course'
),
]))
.
limit
(
1
))
if
not
matching_courses
:
return
course_key
self
.
_course_run_cache
[
cache_key
]
=
matching_courses
[
0
][
'_id'
][
'name'
]
return
course_key
.
replace
(
run
=
self
.
_course_run_cache
[
cache_key
])
def
_compute_metadata_inheritance_tree
(
self
,
course_id
):
'''
TODO (cdodge) This method can be deleted when the 'split module store' work has been completed
...
...
@@ -401,6 +430,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
# get all collections in the course, this query should not return any leaf nodes
# note this is a bit ugly as when we add new categories of containers, we have to add it here
course_id
=
self
.
_fill_in_run
(
course_id
)
block_types_with_children
=
set
(
name
for
name
,
class_
in
XBlock
.
load_classes
()
if
getattr
(
class_
,
'has_children'
,
False
)
)
...
...
@@ -476,6 +506,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
'''
tree
=
{}
course_id
=
self
.
_fill_in_run
(
course_id
)
if
not
force_refresh
:
# see if we are first in the request cache (if present)
if
self
.
request_cache
is
not
None
and
course_id
in
self
.
request_cache
.
data
.
get
(
'metadata_inheritance'
,
{}):
...
...
@@ -554,6 +585,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
data
=
{}
to_process
=
list
(
items
)
course_key
=
self
.
_fill_in_run
(
course_key
)
while
to_process
and
depth
is
None
or
depth
>=
0
:
children
=
[]
for
item
in
to_process
:
...
...
@@ -581,6 +613,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
"""
Load an XModuleDescriptor from item, using the children stored in data_cache
"""
course_key
=
self
.
_fill_in_run
(
course_key
)
location
=
Location
.
_from_deprecated_son
(
item
[
'location'
],
course_key
.
run
)
data_dir
=
getattr
(
item
,
'data_dir'
,
location
.
course
)
root
=
self
.
fs_root
/
data_dir
...
...
@@ -617,6 +650,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
Load a list of xmodules from the data in items, with children cached up
to specified depth
"""
course_key
=
self
.
_fill_in_run
(
course_key
)
data_cache
=
self
.
_cache_children
(
course_key
,
items
,
depth
)
# if we are loading a course object, if we're not prefetching children (depth != 0) then don't
...
...
@@ -669,6 +703,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
Get the course with the given courseid (org/course/run)
"""
assert
(
isinstance
(
course_key
,
SlashSeparatedCourseKey
))
course_key
=
self
.
_fill_in_run
(
course_key
)
location
=
course_key
.
make_usage_key
(
'course'
,
course_key
.
run
)
try
:
return
self
.
get_item
(
location
,
depth
=
depth
)
...
...
@@ -685,6 +720,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
otherwise, do a case sensitive search
"""
assert
(
isinstance
(
course_key
,
SlashSeparatedCourseKey
))
course_key
=
self
.
_fill_in_run
(
course_key
)
location
=
course_key
.
make_usage_key
(
'course'
,
course_key
.
run
)
if
ignore_case
:
course_query
=
location
.
to_deprecated_son
(
'_id.'
)
...
...
@@ -873,6 +909,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
:param runtime: if you already have an xblock from the course, the xblock.runtime value
:param fields: a dictionary of field names and values for the new xmodule
"""
location
=
location
.
replace
(
run
=
self
.
_fill_in_run
(
location
.
course_key
)
.
run
)
# differs from split mongo in that I believe most of this logic should be above the persistence
# layer but added it here to enable quick conversion. I'll need to reconcile these.
if
metadata
is
None
:
...
...
@@ -1073,6 +1110,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
"""
Return an array of all of the locations (deprecated string format) for orphans in the course.
"""
course_key
=
self
.
_fill_in_run
(
course_key
)
detached_categories
=
[
name
for
name
,
__
in
XBlock
.
load_tagged_classes
(
"detached"
)]
query
=
self
.
_course_key_to_son
(
course_key
)
query
[
'_id.category'
]
=
{
'$nin'
:
detached_categories
}
...
...
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