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
ca0dd839
Commit
ca0dd839
authored
Feb 24, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mixed no longer translates
parent
432249e9
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
245 additions
and
423 deletions
+245
-423
cms/djangoapps/contentstore/tests/test_export_git.py
+3
-2
cms/djangoapps/contentstore/views/item.py
+6
-1
cms/envs/bok_choy.py
+1
-1
common/lib/xmodule/xmodule/modulestore/__init__.py
+3
-1
common/lib/xmodule/xmodule/modulestore/locator.py
+31
-18
common/lib/xmodule/xmodule/modulestore/mixed.py
+127
-319
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+1
-2
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
+2
-2
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+2
-2
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
+4
-2
common/lib/xmodule/xmodule/modulestore/tests/test_locators.py
+3
-2
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
+62
-69
lms/envs/acceptance.py
+0
-1
lms/envs/cms/dev.py
+0
-1
No files found.
cms/djangoapps/contentstore/tests/test_export_git.py
View file @
ca0dd839
...
@@ -17,6 +17,7 @@ from .utils import CourseTestCase
...
@@ -17,6 +17,7 @@ from .utils import CourseTestCase
import
contentstore.git_export_utils
as
git_export_utils
import
contentstore.git_export_utils
as
git_export_utils
from
xmodule.contentstore.django
import
_CONTENTSTORE
from
xmodule.contentstore.django
import
_CONTENTSTORE
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
contentstore.utils
import
get_modulestore
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
...
@@ -70,7 +71,7 @@ class TestExportGit(CourseTestCase):
...
@@ -70,7 +71,7 @@ class TestExportGit(CourseTestCase):
Test failed course export response.
Test failed course export response.
"""
"""
self
.
course_module
.
giturl
=
'foobar'
self
.
course_module
.
giturl
=
'foobar'
modulestore
()
.
save_xmodule
(
self
.
course_module
)
get_modulestore
(
self
.
course_module
.
location
)
.
update_item
(
self
.
course_module
)
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
self
.
assertIn
(
'Export Failed:'
,
response
.
content
)
self
.
assertIn
(
'Export Failed:'
,
response
.
content
)
...
@@ -93,7 +94,7 @@ class TestExportGit(CourseTestCase):
...
@@ -93,7 +94,7 @@ class TestExportGit(CourseTestCase):
self
.
populateCourse
()
self
.
populateCourse
()
self
.
course_module
.
giturl
=
'file://{}'
.
format
(
bare_repo_dir
)
self
.
course_module
.
giturl
=
'file://{}'
.
format
(
bare_repo_dir
)
modulestore
()
.
save_xmodule
(
self
.
course_module
)
get_modulestore
(
self
.
course_module
.
location
)
.
update_item
(
self
.
course_module
)
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
self
.
assertIn
(
'Export Succeeded'
,
response
.
content
)
self
.
assertIn
(
'Export Succeeded'
,
response
.
content
)
cms/djangoapps/contentstore/views/item.py
View file @
ca0dd839
...
@@ -202,7 +202,12 @@ def xblock_view_handler(request, package_id, view_name, tag=None, branch=None, v
...
@@ -202,7 +202,12 @@ def xblock_view_handler(request, package_id, view_name, tag=None, branch=None, v
log
.
debug
(
"unable to render studio_view for
%
r"
,
component
,
exc_info
=
True
)
log
.
debug
(
"unable to render studio_view for
%
r"
,
component
,
exc_info
=
True
)
fragment
=
Fragment
(
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)}))
fragment
=
Fragment
(
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)}))
store
.
save_xmodule
(
component
)
# change not authored by requestor but by xblocks. should not convert to draft if not
# already draft
if
getattr
(
component
,
'is_draft'
,
False
):
modulestore
(
'draft'
)
.
update_item
(
component
,
None
)
else
:
modulestore
(
'direct'
)
.
update_item
(
component
,
None
)
elif
view_name
==
'student_view'
and
component
.
has_children
:
elif
view_name
==
'student_view'
and
component
.
has_children
:
# For non-leaf xblocks on the unit page, show the special rendering
# For non-leaf xblocks on the unit page, show the special rendering
# which links to the new container page.
# which links to the new container page.
...
...
cms/envs/bok_choy.py
View file @
ca0dd839
...
@@ -16,7 +16,7 @@ os.environ['SERVICE_VARIANT'] = 'bok_choy'
...
@@ -16,7 +16,7 @@ os.environ['SERVICE_VARIANT'] = 'bok_choy'
os
.
environ
[
'CONFIG_ROOT'
]
=
path
(
__file__
)
.
abspath
()
.
dirname
()
#pylint: disable=E1120
os
.
environ
[
'CONFIG_ROOT'
]
=
path
(
__file__
)
.
abspath
()
.
dirname
()
#pylint: disable=E1120
from
.aws
import
*
# pylint: disable=W0401, W0614
from
.aws
import
*
# pylint: disable=W0401, W0614
from
xmodule.
x_modul
e
import
prefer_xmodules
from
xmodule.
modulestor
e
import
prefer_xmodules
######################### Testing overrides ####################################
######################### Testing overrides ####################################
...
...
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
ca0dd839
...
@@ -479,7 +479,9 @@ class ModuleStoreReadBase(ModuleStoreRead):
...
@@ -479,7 +479,9 @@ class ModuleStoreReadBase(ModuleStoreRead):
metadata_inheritance_cache_subsystem
=
None
,
request_cache
=
None
,
metadata_inheritance_cache_subsystem
=
None
,
request_cache
=
None
,
modulestore_update_signal
=
None
,
xblock_mixins
=
(),
xblock_select
=
None
,
modulestore_update_signal
=
None
,
xblock_mixins
=
(),
xblock_select
=
None
,
# temporary parms to enable backward compatibility. remove once all envs migrated
# temporary parms to enable backward compatibility. remove once all envs migrated
db
=
None
,
collection
=
None
,
host
=
None
,
port
=
None
,
tz_aware
=
True
,
user
=
None
,
password
=
None
db
=
None
,
collection
=
None
,
host
=
None
,
port
=
None
,
tz_aware
=
True
,
user
=
None
,
password
=
None
,
# allow lower level init args to pass harmlessly
**
kwargs
):
):
'''
'''
Set up the error-tracking logic.
Set up the error-tracking logic.
...
...
common/lib/xmodule/xmodule/modulestore/locator.py
View file @
ca0dd839
...
@@ -51,6 +51,12 @@ class Locator(object):
...
@@ -51,6 +51,12 @@ class Locator(object):
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
return
self
.
__dict__
==
other
.
__dict__
return
self
.
__dict__
==
other
.
__dict__
def
__hash__
(
self
):
"""
Hash on contents.
"""
return
hash
(
unicode
(
self
))
def
__repr__
(
self
):
def
__repr__
(
self
):
'''
'''
repr(self) returns something like this: CourseLocator("mit.eecs.6002x")
repr(self) returns something like this: CourseLocator("mit.eecs.6002x")
...
@@ -198,16 +204,16 @@ class CourseLocator(Locator):
...
@@ -198,16 +204,16 @@ class CourseLocator(Locator):
"""
"""
Return a string representing this location.
Return a string representing this location.
"""
"""
result
=
u""
if
self
.
package_id
:
if
self
.
package_id
:
result
=
unicode
(
self
.
package_id
)
result
+
=
unicode
(
self
.
package_id
)
if
self
.
branch
:
if
self
.
branch
:
result
+=
'/'
+
BRANCH_PREFIX
+
self
.
branch
result
+=
'/'
+
BRANCH_PREFIX
+
self
.
branch
return
result
if
self
.
version_guid
:
elif
self
.
version_guid
:
if
self
.
package_id
:
return
u"{prefix}{guid}"
.
format
(
prefix
=
VERSION_PREFIX
,
guid
=
self
.
version_guid
)
result
+=
u"/"
else
:
result
+=
u"{prefix}{guid}"
.
format
(
prefix
=
VERSION_PREFIX
,
guid
=
self
.
version_guid
)
# raise InsufficientSpecificationError("missing package_id or version_guid")
return
result
return
'<InsufficientSpecificationError: missing package_id or version_guid>'
def
url
(
self
):
def
url
(
self
):
"""
"""
...
@@ -432,22 +438,29 @@ class BlockUsageLocator(CourseLocator):
...
@@ -432,22 +438,29 @@ class BlockUsageLocator(CourseLocator):
def
version_agnostic
(
self
):
def
version_agnostic
(
self
):
"""
"""
Returns a copy of itself.
If both version_guid and package_id are known, use a blank package_id in the copy.
We don't care if the locator's version is not the current head; so, avoid version conflict
We don't care if the locator's version is not the current head; so, avoid version conflict
by reducing info.
by reducing info.
Returns a copy of itself without any version info.
:raises: ValueError if the block locator has no package_id
:param block_locator:
:param block_locator:
"""
"""
if
self
.
version_guid
:
return
BlockUsageLocator
(
package_id
=
self
.
package_id
,
return
BlockUsageLocator
(
version_guid
=
self
.
version_guid
,
branch
=
self
.
branch
,
branch
=
self
.
branch
,
block_id
=
self
.
block_id
)
block_id
=
self
.
block_id
)
else
:
def
course_agnostic
(
self
):
return
BlockUsageLocator
(
package_id
=
self
.
package_id
,
"""
branch
=
self
.
branch
,
We only care about the locator's version not its course.
block_id
=
self
.
block_id
)
Returns a copy of itself without any course info.
:raises: ValueError if the block locator has no version_guid
:param block_locator:
"""
return
BlockUsageLocator
(
version_guid
=
self
.
version_guid
,
block_id
=
self
.
block_id
)
def
set_block_id
(
self
,
new
):
def
set_block_id
(
self
,
new
):
"""
"""
...
...
common/lib/xmodule/xmodule/modulestore/mixed.py
View file @
ca0dd839
...
@@ -5,58 +5,41 @@ In this way, courses can be served up both - say - XMLModuleStore or MongoModule
...
@@ -5,58 +5,41 @@ In this way, courses can be served up both - say - XMLModuleStore or MongoModule
"""
"""
import
re
from
importlib
import
import_module
import
logging
import
logging
from
xblock.fields
import
Reference
,
ReferenceList
,
String
from
.
import
ModuleStoreWriteBase
from
.
import
ModuleStoreWriteBase
from
xmodule.modulestore.django
import
create_modulestore_instance
,
loc_mapper
from
xmodule.modulestore.django
import
create_modulestore_instance
,
loc_mapper
from
xmodule.modulestore
import
Location
,
SPLIT_MONGO_MODULESTORE_TYPE
from
xmodule.modulestore
import
Location
,
SPLIT_MONGO_MODULESTORE_TYPE
from
xmodule.modulestore.locator
import
CourseLocator
,
BlockUsageLocator
from
xmodule.modulestore.locator
import
CourseLocator
from
xmodule.modulestore.exceptions
import
InsufficientSpecificationError
,
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
InvalidLocationError
from
xmodule.modulestore.parsers
import
ALLOWED_ID_CHARS
from
uuid
import
uuid4
from
uuid
import
uuid4
from
xmodule.modulestore.mongo.base
import
MongoModuleStore
from
xmodule.modulestore.split_mongo.split
import
SplitMongoModuleStore
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
class
MixedModuleStore
(
ModuleStoreWriteBase
):
class
MixedModuleStore
(
ModuleStoreWriteBase
):
"""
"""
ModuleStore knows how to route requests to the right persistence ms and how to convert any
ModuleStore knows how to route requests to the right persistence ms
references in the xblocks to the type required by the app and the persistence layer.
"""
"""
def
__init__
(
self
,
mappings
,
stores
,
reference_type
=
None
,
i18n_service
=
None
,
**
kwargs
):
def
__init__
(
self
,
mappings
,
stores
,
i18n_service
=
None
,
**
kwargs
):
"""
"""
Initialize a MixedModuleStore. Here we look into our passed in kwargs which should be a
Initialize a MixedModuleStore. Here we look into our passed in kwargs which should be a
collection of other modulestore configuration informations
collection of other modulestore configuration informations
:param reference_type: either a class object such as Locator or Location or the fully
qualified dot-path to that class def to indicate what type of reference the app
uses.
"""
"""
super
(
MixedModuleStore
,
self
)
.
__init__
(
**
kwargs
)
super
(
MixedModuleStore
,
self
)
.
__init__
(
**
kwargs
)
self
.
modulestores
=
{}
self
.
modulestores
=
{}
self
.
mappings
=
mappings
self
.
mappings
=
mappings
# temporary code for transition period
if
reference_type
is
None
:
log
.
warn
(
"reference_type not specified in MixedModuleStore settings.
%
s"
,
"Will default temporarily to the to-be-deprecated Location."
)
self
.
reference_type
=
Location
elif
isinstance
(
reference_type
,
basestring
):
module_path
,
_
,
class_name
=
reference_type
.
rpartition
(
'.'
)
class_
=
getattr
(
import_module
(
module_path
),
class_name
)
self
.
reference_type
=
class_
else
:
self
.
reference_type
=
reference_type
if
'default'
not
in
stores
:
if
'default'
not
in
stores
:
raise
Exception
(
'Missing a default modulestore in the MixedModuleStore __init__ method.'
)
raise
Exception
(
'Missing a default modulestore in the MixedModuleStore __init__ method.'
)
for
key
,
store
in
stores
.
items
():
for
key
,
store
in
stores
.
ite
rite
ms
():
is_xml
=
'XMLModuleStore'
in
store
[
'ENGINE'
]
is_xml
=
'XMLModuleStore'
in
store
[
'ENGINE'
]
if
is_xml
:
if
is_xml
:
# restrict xml to only load courses in mapping
store
[
'OPTIONS'
][
'course_ids'
]
=
[
store
[
'OPTIONS'
][
'course_ids'
]
=
[
course_id
course_id
for
course_id
,
store_key
in
self
.
mappings
.
iteritems
()
for
course_id
,
store_key
in
self
.
mappings
.
iteritems
()
...
@@ -69,8 +52,8 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -69,8 +52,8 @@ class MixedModuleStore(ModuleStoreWriteBase):
store
[
'OPTIONS'
],
store
[
'OPTIONS'
],
i18n_service
=
i18n_service
,
i18n_service
=
i18n_service
,
)
)
#
it would be better to have a notion of read-only rather than hardcode
#
If and when locations can identify their course, we won't need
#
key name
#
these loc maps. They're needed for figuring out which store owns these locations.
if
is_xml
:
if
is_xml
:
self
.
ensure_loc_maps_exist
(
key
)
self
.
ensure_loc_maps_exist
(
key
)
...
@@ -85,148 +68,6 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -85,148 +68,6 @@ class MixedModuleStore(ModuleStoreWriteBase):
mapping
=
self
.
mappings
.
get
(
course_id
,
'default'
)
mapping
=
self
.
mappings
.
get
(
course_id
,
'default'
)
return
self
.
modulestores
[
mapping
]
return
self
.
modulestores
[
mapping
]
# TODO move the location converters to a helper class which returns a converter object w/ 2
# methods: convert_xblock and convert_reference. Then have mixed get the converter and use it.
def
_locator_to_location
(
self
,
reference
):
"""
Convert the referenced locator to a location casting to and from a string as necessary
"""
stringify
=
isinstance
(
reference
,
basestring
)
if
stringify
:
reference
=
BlockUsageLocator
(
url
=
reference
)
location
=
loc_mapper
()
.
translate_locator_to_location
(
reference
)
return
location
.
url
()
if
stringify
else
location
def
_location_to_locator
(
self
,
course_id
,
reference
):
"""
Convert the referenced location to a locator casting to and from a string as necessary
"""
stringify
=
isinstance
(
reference
,
basestring
)
if
stringify
:
reference
=
Location
(
reference
)
locator
=
loc_mapper
()
.
translate_location
(
course_id
,
reference
,
reference
.
revision
==
None
,
True
)
return
unicode
(
locator
)
if
stringify
else
locator
def
_incoming_reference_adaptor
(
self
,
store
,
course_id
,
reference
):
"""
Convert the reference to the type the persistence layer wants
"""
if
reference
is
None
:
return
None
if
issubclass
(
store
.
reference_type
,
self
.
reference_type
):
return
reference
if
store
.
reference_type
==
Location
:
return
self
.
_locator_to_location
(
reference
)
return
self
.
_location_to_locator
(
course_id
,
reference
)
def
_outgoing_reference_adaptor
(
self
,
store
,
course_id
,
reference
):
"""
Convert the reference to the type the application wants
"""
if
reference
is
None
:
return
None
if
issubclass
(
store
.
reference_type
,
self
.
reference_type
):
return
reference
if
store
.
reference_type
==
Location
:
return
self
.
_location_to_locator
(
course_id
,
reference
)
return
self
.
_locator_to_location
(
reference
)
def
_xblock_adaptor_iterator
(
self
,
adaptor
,
string_converter
,
store
,
course_id
,
xblock
):
"""
Change all reference fields in this xblock to the type expected by the receiving layer
"""
xblock
.
location
=
adaptor
(
store
,
course_id
,
xblock
.
location
)
for
field
in
xblock
.
fields
.
itervalues
():
if
field
.
is_set_on
(
xblock
):
if
isinstance
(
field
,
Reference
):
field
.
write_to
(
xblock
,
adaptor
(
store
,
course_id
,
field
.
read_from
(
xblock
))
)
elif
isinstance
(
field
,
ReferenceList
):
field
.
write_to
(
xblock
,
[
adaptor
(
store
,
course_id
,
ref
)
for
ref
in
field
.
read_from
(
xblock
)
]
)
elif
isinstance
(
field
,
String
):
# replace links within the string
string_converter
(
field
,
xblock
)
return
xblock
def
_incoming_xblock_adaptor
(
self
,
store
,
course_id
,
xblock
):
"""
Change all reference fields in this xblock to the type expected by the persistence layer
"""
string_converter
=
self
.
_get_string_converter
(
course_id
,
store
.
reference_type
,
xblock
.
scope_ids
.
usage_id
)
return
self
.
_xblock_adaptor_iterator
(
self
.
_incoming_reference_adaptor
,
string_converter
,
store
,
course_id
,
xblock
)
def
_outgoing_xblock_adaptor
(
self
,
store
,
course_id
,
xblock
):
"""
Change all reference fields in this xblock to the type expected by the persistence layer
"""
string_converter
=
self
.
_get_string_converter
(
course_id
,
xblock
.
scope_ids
.
usage_id
.
__class__
,
xblock
.
scope_ids
.
usage_id
)
return
self
.
_xblock_adaptor_iterator
(
self
.
_outgoing_reference_adaptor
,
string_converter
,
store
,
course_id
,
xblock
)
CONVERT_RE
=
re
.
compile
(
r"/jump_to_id/({}+)"
.
format
(
ALLOWED_ID_CHARS
))
def
_get_string_converter
(
self
,
course_id
,
reference_type
,
from_base_addr
):
"""
Return a closure which finds and replaces all embedded links in a string field
with the correct rewritten link for the target type
"""
if
issubclass
(
self
.
reference_type
,
reference_type
):
return
lambda
field
,
xblock
:
None
if
isinstance
(
from_base_addr
,
Location
):
def
mapper
(
found_id
):
"""
Convert the found id to BlockUsageLocator block_id
"""
location
=
from_base_addr
.
replace
(
category
=
None
,
name
=
found_id
)
# NOTE without category, it cannot create a new mapping if there's not one already
return
loc_mapper
()
.
translate_location
(
course_id
,
location
)
.
block_id
else
:
def
mapper
(
found_id
):
"""
Convert the found id to Location block_id
"""
locator
=
BlockUsageLocator
.
make_relative
(
from_base_addr
,
found_id
)
return
loc_mapper
()
.
translate_locator_to_location
(
locator
)
.
name
def
converter
(
field
,
xblock
):
"""
Find all of the ids in the block and replace them w/ their mapped values
"""
value
=
field
.
read_from
(
xblock
)
self
.
CONVERT_RE
.
sub
(
mapper
,
value
)
field
.
write_to
(
xblock
,
value
)
return
converter
def
ensure_loc_maps_exist
(
self
,
store_name
):
"""
Ensure location maps exist for every course in the modulestore whose
name is the given name (mostly used for 'xml'). It creates maps for any
missing ones.
NOTE: will only work if the given store is Location based. If it's not,
it raises NotImplementedError
"""
store
=
self
.
modulestores
[
store_name
]
if
store
.
reference_type
!=
Location
:
raise
NotImplementedError
(
u"Cannot create maps from
%
s"
,
store
.
reference_type
)
for
course
in
store
.
get_courses
():
loc_mapper
()
.
translate_location
(
course
.
location
.
course_id
,
course
.
location
)
def
has_item
(
self
,
course_id
,
reference
):
def
has_item
(
self
,
course_id
,
reference
):
"""
"""
Does the course include the xblock who's id is reference?
Does the course include the xblock who's id is reference?
...
@@ -235,21 +76,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -235,21 +76,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
:param reference: a Location or BlockUsageLocator
:param reference: a Location or BlockUsageLocator
"""
"""
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
decoded_ref
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
reference
)
return
store
.
has_item
(
course_id
,
reference
)
return
store
.
has_item
(
course_id
,
decoded_ref
)
def
get_item
(
self
,
location
,
depth
=
0
):
def
get_item
(
self
,
location
,
depth
=
0
):
"""
"""
This method is explicitly not implemented as we need a course_id to disambiguate
This method is explicitly not implemented as we need a course_id to disambiguate
We should be able to fix this when the data-model rearchitecting is done
We should be able to fix this when the data-model rearchitecting is done
"""
"""
# Although we shouldn't have both get_item and get_instance imho
raise
NotImplementedError
raise
NotImplementedError
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
decoded_ref
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
location
)
return
store
.
get_instance
(
course_id
,
location
,
depth
)
xblock
=
store
.
get_instance
(
course_id
,
decoded_ref
,
depth
)
return
self
.
_outgoing_xblock_adaptor
(
store
,
course_id
,
xblock
)
def
get_items
(
self
,
location
,
course_id
=
None
,
depth
=
0
,
qualifiers
=
None
):
def
get_items
(
self
,
location
,
course_id
=
None
,
depth
=
0
,
qualifiers
=
None
):
"""
"""
...
@@ -262,44 +101,15 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -262,44 +101,15 @@ class MixedModuleStore(ModuleStoreWriteBase):
a Locator with at least a package_id and branch but possibly no block_id.
a Locator with at least a package_id and branch but possibly no block_id.
depth: An argument that some module stores may use to prefetch
depth: An argument that some module stores may use to prefetch
descend
e
nts of the queried modules for more efficient results later
descend
a
nts of the queried modules for more efficient results later
in the request. The depth is counted in the number of calls to
in the request. The depth is counted in the number of calls to
get_children() to cache. None indicates to cache all descend
e
nts
get_children() to cache. None indicates to cache all descend
a
nts
"""
"""
if
not
(
course_id
or
hasattr
(
location
,
'package_id'
)):
if
not
(
course_id
or
hasattr
(
location
,
'package_id'
)):
raise
Exception
(
"Must pass in a course_id when calling get_items()"
)
raise
Exception
(
"Must pass in a course_id when calling get_items()"
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
or
getattr
(
location
,
'package_id'
))
store
=
self
.
_get_modulestore_for_courseid
(
course_id
or
getattr
(
location
,
'package_id'
))
if
not
issubclass
(
self
.
reference_type
,
store
.
reference_type
):
return
store
.
get_items
(
location
,
course_id
,
depth
,
qualifiers
)
if
store
.
reference_type
==
Location
:
if
getattr
(
location
,
'block_id'
,
False
):
location
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
location
)
else
:
# get the course's location
location
=
loc_mapper
()
.
translate_locator_to_location
(
location
,
get_course
=
True
)
# now remove the unknowns
location
=
location
.
replace
(
category
=
qualifiers
.
get
(
'category'
,
None
),
name
=
None
)
else
:
if
not
isinstance
(
location
,
Location
):
location
=
Location
(
location
)
try
:
location
.
ensure_fully_specified
()
location
=
loc_mapper
()
.
translate_location
(
course_id
,
location
,
location
.
revision
==
None
,
True
)
except
InsufficientSpecificationError
:
# construct the Locator by hand
if
location
.
category
is
not
None
and
qualifiers
.
get
(
'category'
,
False
):
qualifiers
[
'category'
]
=
location
.
category
location
=
loc_mapper
()
.
translate_location_to_course_locator
(
course_id
,
location
,
location
.
revision
==
None
)
xblocks
=
store
.
get_items
(
location
,
course_id
,
depth
,
qualifiers
)
xblocks
=
[
self
.
_outgoing_xblock_adaptor
(
store
,
course_id
,
xblock
)
for
xblock
in
xblocks
]
return
xblocks
def
_get_course_id_from_course_location
(
self
,
course_location
):
def
_get_course_id_from_course_location
(
self
,
course_location
):
"""
"""
...
@@ -312,35 +122,39 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -312,35 +122,39 @@ class MixedModuleStore(ModuleStoreWriteBase):
Returns a list containing the top level XModuleDescriptors of the courses
Returns a list containing the top level XModuleDescriptors of the courses
in this modulestore.
in this modulestore.
'''
'''
courses
=
[]
courses
=
{}
for
key
in
self
.
modulestores
:
# order the modulestores and ensure no dupes: an awkward bit of hardcoding to ensure precedence
store
=
self
.
modulestores
[
key
]
# xml is in here because mappings trump discovery
stores
=
[
self
.
modulestores
[
'default'
],
self
.
modulestores
[
'xml'
]]
for
key
,
store
in
self
.
modulestores
.
iteritems
():
# awkward hardcoding of knowledge that 'draft' is a dupe of 'direct'
if
key
!=
'draft'
and
store
not
in
stores
:
stores
.
append
(
store
)
has_locators
=
False
for
store
in
stores
:
store_courses
=
store
.
get_courses
()
store_courses
=
store
.
get_courses
()
# If the store has not been labeled as 'default' then we should
# filter out ones which were fetched from earlier stores but locations may not be ==
# only surface courses that have a mapping entry, for example the XMLModuleStore will
for
course
in
store_courses
:
# slurp up anything that is on disk, however, we don't want to surface those to
course_location
=
unicode
(
course
.
location
)
# consumers *unless* there is an explicit mapping in the configuration
if
course_location
not
in
courses
:
# TODO obviously this filtering only applies to filebased stores
if
has_locators
and
isinstance
(
course
.
location
,
Location
):
if
key
!=
'default'
:
try
:
for
course
in
store_courses
:
# if there's no existing mapping, then the course can't have been in split
course_id
=
self
.
_get_course_id_from_course_location
(
course
.
location
)
course_locator
=
loc_mapper
()
.
translate_location
(
# make sure that the courseId is mapped to the store in question
course
.
location
.
course_id
,
course
.
location
,
add_entry_if_missing
=
False
if
key
==
self
.
mappings
.
get
(
course_id
,
'default'
):
)
courses
.
append
(
if
unicode
(
course_locator
)
not
in
courses
:
self
.
_outgoing_reference_adaptor
(
store
,
course_id
,
course
.
location
)
courses
[
course_location
]
=
course
)
except
ItemNotFoundError
:
else
:
courses
[
course_location
]
=
course
# if we're the 'default' store provider, then we surface all courses hosted in
elif
isinstance
(
course
.
location
,
CourseLocator
):
# that store provider
has_locators
=
True
store_courses
=
[
courses
[
course_location
]
=
course
self
.
_outgoing_reference_adaptor
(
else
:
store
,
self
.
_get_course_id_from_course_location
(
course
.
location
),
course
.
location
courses
[
course_location
]
=
course
)
for
course
in
store_courses
return
courses
.
values
()
]
courses
=
courses
+
store_courses
return
courses
def
get_course
(
self
,
course_id
):
def
get_course
(
self
,
course_id
):
"""
"""
...
@@ -350,46 +164,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -350,46 +164,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
:param course_id: must be either a string course_id or a CourseLocator
:param course_id: must be either a string course_id or a CourseLocator
"""
"""
store
=
self
.
_get_modulestore_for_courseid
(
store
=
self
.
_get_modulestore_for_courseid
(
course_id
.
package_id
if
hasattr
(
course_id
,
'package_id'
)
else
course_id
)
course_id
.
package_id
if
hasattr
(
course_id
,
'package_id'
)
else
course_id
)
try
:
try
:
# translate won't work w/ missing fields so work around it
return
store
.
get_course
(
course_id
)
if
store
.
reference_type
==
Location
:
# takes the course_id: figure out if this is old or new style
if
not
issubclass
(
store
.
reference_type
,
self
.
reference_type
):
if
isinstance
(
course_id
,
basestring
):
course_id
=
CourseLocator
(
package_id
=
course_id
,
branch
=
'published'
)
course_location
=
loc_mapper
()
.
translate_locator_to_location
(
course_id
,
get_course
=
True
)
course_id
=
course_location
.
course_id
xblock
=
store
.
get_course
(
course_id
)
else
:
# takes a courseLocator
if
isinstance
(
course_id
,
CourseLocator
):
location
=
course_id
course_id
=
None
# not an old style course_id; so, don't use it further
elif
'/'
in
course_id
:
location
=
loc_mapper
()
.
translate_location_to_course_locator
(
course_id
,
None
,
True
)
else
:
location
=
CourseLocator
(
package_id
=
course_id
,
branch
=
'published'
)
course_id
=
None
# not an old style course_id; so, don't use it further
xblock
=
store
.
get_course
(
location
)
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
None
return
None
if
xblock
is
not
None
:
return
self
.
_outgoing_xblock_adaptor
(
store
,
course_id
,
xblock
)
else
:
return
None
def
get_parent_locations
(
self
,
location
,
course_id
):
def
get_parent_locations
(
self
,
location
,
course_id
):
"""
"""
returns the parent locations for a given location and course_id
returns the parent locations for a given location and course_id
"""
"""
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
decoded_ref
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
location
)
return
store
.
get_parent_locations
(
location
,
course_id
)
parents
=
store
.
get_parent_locations
(
decoded_ref
,
course_id
)
return
[
self
.
_outgoing_reference_adaptor
(
store
,
course_id
,
reference
)
for
reference
in
parents
]
def
get_modulestore_type
(
self
,
course_id
):
def
get_modulestore_type
(
self
,
course_id
):
"""
"""
...
@@ -409,8 +196,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -409,8 +196,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
"""
"""
course_id
=
getattr
(
course_location
,
'course_id'
,
getattr
(
course_location
,
'package_id'
,
None
))
course_id
=
getattr
(
course_location
,
'course_id'
,
getattr
(
course_location
,
'package_id'
,
None
))
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
decoded_ref
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
course_location
)
return
store
.
get_orphans
(
course_location
,
branch
)
return
store
.
get_orphans
(
decoded_ref
,
branch
)
def
get_errored_courses
(
self
):
def
get_errored_courses
(
self
):
"""
"""
...
@@ -426,13 +212,16 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -426,13 +212,16 @@ class MixedModuleStore(ModuleStoreWriteBase):
"""
"""
Get the course_id from the block or from asking its store. Expensive.
Get the course_id from the block or from asking its store. Expensive.
"""
"""
if
block
.
course_id
is
not
None
:
try
:
return
block
.
course_id
if
block
.
course_id
is
not
None
:
return
block
.
course_id
except
AssertionError
:
# will occur if no xmodule set
pass
try
:
try
:
course
=
store
.
_get_course_for_item
(
block
.
scope_ids
.
usage_id
)
course
=
store
.
_get_course_for_item
(
block
.
scope_ids
.
usage_id
)
if
course
:
if
course
:
return
course
.
scope_ids
.
usage_id
.
course_id
return
course
.
scope_ids
.
usage_id
.
course_id
except
:
# sorry, that method just raises vanilla Exception
except
:
# sorry, that method just raises vanilla Exception
if it doesn't find course
pass
pass
def
_infer_course_id_try
(
self
,
location
):
def
_infer_course_id_try
(
self
,
location
):
...
@@ -442,10 +231,27 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -442,10 +231,27 @@ class MixedModuleStore(ModuleStoreWriteBase):
proper modulestore. This method attempts several sound but not complete methods.
proper modulestore. This method attempts several sound but not complete methods.
:param location: an old style Location
:param location: an old style Location
"""
"""
if
isinstance
(
location
,
CourseLocator
):
return
location
.
package_id
elif
isinstance
(
location
,
basestring
):
try
:
location
=
Location
(
location
)
except
InvalidLocationError
:
# try to parse as a course_id
try
:
Location
.
parse_course_id
(
location
)
# it's already a course_id
return
location
except
ValueError
:
# cannot interpret the location
return
None
# location is a Location at this point
if
location
.
category
==
'course'
:
# easiest case
if
location
.
category
==
'course'
:
# easiest case
return
location
.
course_id
return
location
.
course_id
# try finding in loc_mapper
# try finding in loc_mapper
try
:
try
:
# see if the loc mapper knows the course id (requires double translation)
locator
=
loc_mapper
()
.
translate_location_to_course_locator
(
None
,
location
)
locator
=
loc_mapper
()
.
translate_location_to_course_locator
(
None
,
location
)
location
=
loc_mapper
()
.
translate_locator_to_location
(
locator
,
get_course
=
True
)
location
=
loc_mapper
()
.
translate_locator_to_location
(
locator
,
get_course
=
True
)
return
location
.
course_id
return
location
.
course_id
...
@@ -455,16 +261,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -455,16 +261,19 @@ class MixedModuleStore(ModuleStoreWriteBase):
for
store
in
self
.
modulestores
.
itervalues
():
for
store
in
self
.
modulestores
.
itervalues
():
if
isinstance
(
location
,
store
.
reference_type
):
if
isinstance
(
location
,
store
.
reference_type
):
try
:
try
:
block
=
store
.
get_item
(
location
)
x
block
=
store
.
get_item
(
location
)
course_id
=
self
.
_get_course_id_from_block
(
block
,
store
)
course_id
=
self
.
_get_course_id_from_block
(
x
block
,
store
)
if
course_id
is
not
None
:
if
course_id
is
not
None
:
return
course_id
return
course_id
except
NotImplementedError
:
except
NotImplementedError
:
blocks
=
store
.
get_items
(
location
)
blocks
=
store
.
get_items
(
location
)
if
len
(
blocks
)
==
1
:
if
len
(
blocks
)
==
1
:
block
=
blocks
[
0
]
block
=
blocks
[
0
]
if
block
.
course_id
is
not
None
:
try
:
return
block
.
course_id
if
block
.
course_id
is
not
None
:
return
block
.
course_id
except
AssertionError
:
pass
except
ItemNotFoundError
:
except
ItemNotFoundError
:
pass
pass
# if we get here, it must be in a Locator based store, but we won't be able to find
# if we get here, it must be in a Locator based store, but we won't be able to find
...
@@ -481,19 +290,20 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -481,19 +290,20 @@ class MixedModuleStore(ModuleStoreWriteBase):
NOTE: unlike the other mixed modulestore methods, this does not adapt its argument
NOTE: unlike the other mixed modulestore methods, this does not adapt its argument
to the persistence store but requires its caller to know what the persistence store
to the persistence store but requires its caller to know what the persistence store
wants for args. It does not translate any references on the way in; so, don't
wants for args.
pass children or other reference fields here.
It does, however, adapt the xblock on the way out to the app's
reference_type
:returns: course xblock
:returns: course xblock
"""
"""
store
=
self
.
modulestores
[
store_name
]
store
=
self
.
modulestores
[
store_name
]
if
not
hasattr
(
store
,
'create_course'
):
if
not
hasattr
(
store
,
'create_course'
):
raise
NotImplementedError
(
u"Cannot create a course on store
%
s"
,
store_name
)
raise
NotImplementedError
(
u"Cannot create a course on store
%
s"
%
store_name
)
if
store
.
get_modulestore_type
(
course_location
.
course_id
)
==
SPLIT_MONGO_MODULESTORE_TYPE
:
if
store
.
get_modulestore_type
(
course_location
.
course_id
)
==
SPLIT_MONGO_MODULESTORE_TYPE
:
org
=
kwargs
.
pop
(
'org'
,
course_location
.
org
)
org
=
kwargs
.
pop
(
'org'
,
course_location
.
org
)
pretty_id
=
kwargs
.
pop
(
'pretty_id'
,
None
)
pretty_id
=
kwargs
.
pop
(
'pretty_id'
,
None
)
fields
=
kwargs
.
get
(
'fields'
,
{})
fields
.
update
(
kwargs
.
pop
(
'metadata'
,
{}))
fields
.
update
(
kwargs
.
pop
(
'definition_data'
,
{}))
kwargs
[
'fields'
]
=
fields
# TODO rename id_root to package_id for consistency. It's too confusing
# TODO rename id_root to package_id for consistency. It's too confusing
id_root
=
kwargs
.
pop
(
'id_root'
,
u"{0.org}.{0.course}.{0.name}"
.
format
(
course_location
))
id_root
=
kwargs
.
pop
(
'id_root'
,
u"{0.org}.{0.course}.{0.name}"
.
format
(
course_location
))
course
=
store
.
create_course
(
course
=
store
.
create_course
(
...
@@ -509,7 +319,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -509,7 +319,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
course
=
store
.
create_course
(
course_location
,
**
kwargs
)
course
=
store
.
create_course
(
course_location
,
**
kwargs
)
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
course_location
)
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
course_location
)
return
self
.
_outgoing_xblock_adaptor
(
store
,
course_location
.
course_id
,
course
)
return
course
def
create_item
(
self
,
course_or_parent_loc
,
category
,
user_id
=
None
,
**
kwargs
):
def
create_item
(
self
,
course_or_parent_loc
,
category
,
user_id
=
None
,
**
kwargs
):
"""
"""
...
@@ -520,22 +330,17 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -520,22 +330,17 @@ class MixedModuleStore(ModuleStoreWriteBase):
Adds an entry to the loc map using the kwarg location if provided (must be a
Adds an entry to the loc map using the kwarg location if provided (must be a
Location if provided) or block_id and category if provided.
Location if provided) or block_id and category if provided.
:param course_or_parent_loc:
will be translated appropriately to the course's store.
:param course_or_parent_loc:
Can be a course_id (org/course/run), CourseLocator,
Can be a course_id (org/course/run), CourseLocator, Location, or BlockUsageLocator.
Location, or BlockUsageLocator but must be what the persistence modulestore expects
"""
"""
# find the store for the course
# find the store for the course
if
self
.
reference_type
==
Location
:
course_id
=
self
.
_infer_course_id_try
(
course_or_parent_loc
)
if
hasattr
(
course_or_parent_loc
,
'tag'
):
course_id
=
self
.
_infer_course_id_try
(
course_or_parent_loc
)
else
:
course_id
=
course_or_parent_loc
else
:
course_id
=
course_or_parent_loc
.
package_id
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
location
=
kwargs
.
pop
(
'location'
,
None
)
location
=
kwargs
.
pop
(
'location'
,
None
)
# invoke its create_item
# invoke its create_item
if
store
.
reference_type
==
Location
:
if
isinstance
(
store
,
MongoModuleStore
)
:
# convert parent loc if it's legit
# convert parent loc if it's legit
block_id
=
kwargs
.
pop
(
'block_id'
,
uuid4
()
.
hex
)
block_id
=
kwargs
.
pop
(
'block_id'
,
uuid4
()
.
hex
)
if
isinstance
(
course_or_parent_loc
,
basestring
):
if
isinstance
(
course_or_parent_loc
,
basestring
):
...
@@ -546,7 +351,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -546,7 +351,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
locn_dict
[
'name'
]
=
block_id
locn_dict
[
'name'
]
=
block_id
location
=
Location
(
locn_dict
)
location
=
Location
(
locn_dict
)
else
:
else
:
parent_loc
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
course_or_parent_loc
)
parent_loc
=
course_or_parent_loc
# must have a legitimate location, compute if appropriate
# must have a legitimate location, compute if appropriate
if
location
is
None
:
if
location
is
None
:
location
=
parent_loc
.
replace
(
category
=
category
,
name
=
block_id
)
location
=
parent_loc
.
replace
(
category
=
category
,
name
=
block_id
)
...
@@ -559,7 +364,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -559,7 +364,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
parent
=
store
.
get_item
(
parent_loc
)
parent
=
store
.
get_item
(
parent_loc
)
parent
.
children
.
append
(
location
.
url
())
parent
.
children
.
append
(
location
.
url
())
store
.
update_item
(
parent
)
store
.
update_item
(
parent
)
el
se
:
el
if
isinstance
(
store
,
SplitMongoModuleStore
)
:
if
isinstance
(
course_or_parent_loc
,
basestring
):
# course_id
if
isinstance
(
course_or_parent_loc
,
basestring
):
# course_id
old_course_id
=
course_or_parent_loc
old_course_id
=
course_or_parent_loc
course_or_parent_loc
=
loc_mapper
()
.
translate_location_to_course_locator
(
course_or_parent_loc
=
loc_mapper
()
.
translate_location_to_course_locator
(
...
@@ -570,13 +375,15 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -570,13 +375,15 @@ class MixedModuleStore(ModuleStoreWriteBase):
course_or_parent_loc
,
get_course
=
True
course_or_parent_loc
,
get_course
=
True
)
)
old_course_id
=
old_course_loc
.
course_id
old_course_id
=
old_course_loc
.
course_id
else
:
# it's a Location
else
:
old_course_id
=
course_id
raise
ValueError
(
u"Cannot create a child of {} in split. Wrong repr."
.
format
(
course_or_parent_loc
))
course_or_parent_loc
=
self
.
_location_to_locator
(
course_id
,
course_or_parent_loc
)
# split handles all the fields in one dict not separated by scope
fields
=
kwargs
.
get
(
'fields'
,
{})
fields
=
kwargs
.
get
(
'fields'
,
{})
fields
.
update
(
kwargs
.
pop
(
'metadata'
,
{}))
fields
.
update
(
kwargs
.
pop
(
'metadata'
,
{}))
fields
.
update
(
kwargs
.
pop
(
'definition_data'
,
{}))
fields
.
update
(
kwargs
.
pop
(
'definition_data'
,
{}))
kwargs
[
'fields'
]
=
fields
kwargs
[
'fields'
]
=
fields
xblock
=
store
.
create_item
(
course_or_parent_loc
,
category
,
user_id
,
**
kwargs
)
xblock
=
store
.
create_item
(
course_or_parent_loc
,
category
,
user_id
,
**
kwargs
)
if
location
is
None
:
if
location
is
None
:
locn_dict
=
Location
.
parse_course_id
(
old_course_id
)
locn_dict
=
Location
.
parse_course_id
(
old_course_id
)
...
@@ -587,6 +394,9 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -587,6 +394,9 @@ class MixedModuleStore(ModuleStoreWriteBase):
loc_mapper
()
.
translate_location
(
loc_mapper
()
.
translate_location
(
old_course_id
,
location
,
passed_block_id
=
xblock
.
location
.
block_id
old_course_id
,
location
,
passed_block_id
=
xblock
.
location
.
block_id
)
)
else
:
raise
NotImplementedError
(
u"Cannot create an item on store
%
s"
%
store
)
return
xblock
return
xblock
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
):
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
):
...
@@ -594,37 +404,21 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -594,37 +404,21 @@ class MixedModuleStore(ModuleStoreWriteBase):
Update the xblock persisted to be the same as the given for all types of fields
Update the xblock persisted to be the same as the given for all types of fields
(content, children, and metadata) attribute the change to the given user.
(content, children, and metadata) attribute the change to the given user.
"""
"""
if
self
.
reference_type
==
Location
:
course_id
=
self
.
_infer_course_id_try
(
xblock
.
scope_ids
.
usage_id
)
course_id
=
xblock
.
course_id
if
course_id
is
None
:
if
course_id
is
None
:
raise
ItemNotFoundError
(
u"Cannot find modulestore for
%
s"
%
xblock
.
scope_ids
.
usage_id
)
course_id
=
self
.
_infer_course_id_try
(
xblock
.
scope_ids
.
usage_id
)
if
course_id
is
None
:
raise
ItemNotFoundError
(
u"Cannot find modulestore for
%
s"
,
xblock
.
scope_ids
.
usage_id
)
else
:
locator
=
xblock
.
scope_ids
.
usage_id
course_id
=
locator
.
package_id
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
return
store
.
update_item
(
xblock
,
user_id
)
# if an xblock, convert its contents to correct addr scheme
xblock
=
self
.
_incoming_xblock_adaptor
(
store
,
course_id
,
xblock
)
xblock
=
store
.
update_item
(
xblock
,
user_id
)
return
self
.
_outgoing_xblock_adaptor
(
store
,
course_id
,
xblock
)
def
delete_item
(
self
,
location
,
user_id
=
None
):
def
delete_item
(
self
,
location
,
user_id
=
None
):
"""
"""
Delete the given item from persistence.
Delete the given item from persistence.
"""
"""
if
self
.
reference_type
==
Location
:
course_id
=
self
.
_infer_course_id_try
(
location
)
course_id
=
self
.
_infer_course_id_try
(
location
)
if
course_id
is
None
:
if
course_id
is
None
:
raise
ItemNotFoundError
(
u"Cannot find modulestore for
%
s"
%
location
)
raise
ItemNotFoundError
(
u"Cannot find modulestore for
%
s"
,
location
)
else
:
course_id
=
location
.
package_id
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
return
store
.
delete_item
(
location
,
user_id
=
user_id
)
decoded_ref
=
self
.
_incoming_reference_adaptor
(
store
,
course_id
,
location
)
return
store
.
delete_item
(
decoded_ref
,
user_id
=
user_id
)
def
close_all_connections
(
self
):
def
close_all_connections
(
self
):
"""
"""
...
@@ -636,3 +430,17 @@ class MixedModuleStore(ModuleStoreWriteBase):
...
@@ -636,3 +430,17 @@ class MixedModuleStore(ModuleStoreWriteBase):
elif
hasattr
(
mstore
,
'db'
):
elif
hasattr
(
mstore
,
'db'
):
mstore
.
db
.
connection
.
close
()
mstore
.
db
.
connection
.
close
()
def
ensure_loc_maps_exist
(
self
,
store_name
):
"""
Ensure location maps exist for every course in the modulestore whose
name is the given name (mostly used for 'xml'). It creates maps for any
missing ones.
NOTE: will only work if the given store is Location based. If it's not,
it raises NotImplementedError
"""
store
=
self
.
modulestores
[
store_name
]
if
store
.
reference_type
!=
Location
:
raise
NotImplementedError
(
u"Cannot create maps from
%
s"
%
store
.
reference_type
)
for
course
in
store
.
get_courses
():
loc_mapper
()
.
translate_location
(
course
.
location
.
course_id
,
course
.
location
)
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
ca0dd839
...
@@ -633,8 +633,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
...
@@ -633,8 +633,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
raise
ValueError
(
u"Course roots must be of category 'course': {}"
.
format
(
unicode
(
location
)))
raise
ValueError
(
u"Course roots must be of category 'course': {}"
.
format
(
unicode
(
location
)))
return
self
.
create_and_save_xmodule
(
location
,
definition_data
,
metadata
,
runtime
)
return
self
.
create_and_save_xmodule
(
location
,
definition_data
,
metadata
,
runtime
)
def
create_xmodule
(
self
,
location
,
definition_data
=
None
,
metadata
=
None
,
system
=
None
,
def
create_xmodule
(
self
,
location
,
definition_data
=
None
,
metadata
=
None
,
system
=
None
,
fields
=
{}):
fields
=
{}):
"""
"""
Create the new xmodule but don't save it. Returns the new module.
Create the new xmodule but don't save it. Returns the new module.
...
...
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
View file @
ca0dd839
...
@@ -92,7 +92,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -92,7 +92,7 @@ class DraftModuleStore(MongoModuleStore):
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
location
,
depth
=
depth
))
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
location
,
depth
=
depth
))
def
create_xmodule
(
self
,
location
,
definition_data
=
None
,
metadata
=
None
,
system
=
None
):
def
create_xmodule
(
self
,
location
,
definition_data
=
None
,
metadata
=
None
,
system
=
None
,
fields
=
{}
):
"""
"""
Create the new xmodule but don't save it. Returns the new module with a draft locator
Create the new xmodule but don't save it. Returns the new module with a draft locator
...
@@ -104,7 +104,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -104,7 +104,7 @@ class DraftModuleStore(MongoModuleStore):
draft_loc
=
as_draft
(
location
)
draft_loc
=
as_draft
(
location
)
if
draft_loc
.
category
in
DIRECT_ONLY_CATEGORIES
:
if
draft_loc
.
category
in
DIRECT_ONLY_CATEGORIES
:
raise
InvalidVersionError
(
location
)
raise
InvalidVersionError
(
location
)
return
super
(
DraftModuleStore
,
self
)
.
create_xmodule
(
draft_loc
,
definition_data
,
metadata
,
system
)
return
super
(
DraftModuleStore
,
self
)
.
create_xmodule
(
draft_loc
,
definition_data
,
metadata
,
system
,
fields
)
def
get_items
(
self
,
location
,
course_id
=
None
,
depth
=
0
,
qualifiers
=
None
):
def
get_items
(
self
,
location
,
course_id
=
None
,
depth
=
0
,
qualifiers
=
None
):
"""
"""
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
ca0dd839
...
@@ -556,8 +556,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -556,8 +556,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
The block's history tracks its explicit changes but not the changes in its children.
The block's history tracks its explicit changes but not the changes in its children.
'''
'''
#
version
_agnostic means we don't care if the head and version don't align, trust the version
#
course
_agnostic means we don't care if the head and version don't align, trust the version
course_struct
=
self
.
_lookup_course
(
block_locator
.
version
_agnostic
())[
'structure'
]
course_struct
=
self
.
_lookup_course
(
block_locator
.
course
_agnostic
())[
'structure'
]
block_id
=
block_locator
.
block_id
block_id
=
block_locator
.
block_id
update_version_field
=
'blocks.{}.edit_info.update_version'
.
format
(
block_id
)
update_version_field
=
'blocks.{}.edit_info.update_version'
.
format
(
block_id
)
all_versions_with_block
=
self
.
db_connection
.
find_matching_structures
({
'original_version'
:
course_struct
[
'original_version'
],
all_versions_with_block
=
self
.
db_connection
.
find_matching_structures
({
'original_version'
:
course_struct
[
'original_version'
],
...
...
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
View file @
ca0dd839
...
@@ -33,7 +33,6 @@ def mixed_store_config(data_dir, mappings):
...
@@ -33,7 +33,6 @@ def mixed_store_config(data_dir, mappings):
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'OPTIONS'
:
{
'OPTIONS'
:
{
'mappings'
:
mappings
,
'mappings'
:
mappings
,
'reference_type'
:
'xmodule.modulestore.Location'
,
'stores'
:
{
'stores'
:
{
'default'
:
mongo_config
[
'default'
],
'default'
:
mongo_config
[
'default'
],
'xml'
:
xml_config
[
'default'
]
'xml'
:
xml_config
[
'default'
]
...
@@ -219,14 +218,17 @@ class ModuleStoreTestCase(TestCase):
...
@@ -219,14 +218,17 @@ class ModuleStoreTestCase(TestCase):
# even if we're using a mixed modulestore
# even if we're using a mixed modulestore
store
=
editable_modulestore
()
store
=
editable_modulestore
()
if
hasattr
(
store
,
'collection'
):
if
hasattr
(
store
,
'collection'
):
connection
=
store
.
collection
.
database
.
connection
store
.
collection
.
drop
()
store
.
collection
.
drop
()
store
.
db
.
connection
.
close
()
connection
.
close
()
elif
hasattr
(
store
,
'close_all_connections'
):
elif
hasattr
(
store
,
'close_all_connections'
):
store
.
close_all_connections
()
store
.
close_all_connections
()
if
contentstore
()
.
fs_files
:
if
contentstore
()
.
fs_files
:
db
=
contentstore
()
.
fs_files
.
database
db
=
contentstore
()
.
fs_files
.
database
db
.
connection
.
drop_database
(
db
)
db
.
connection
.
drop_database
(
db
)
db
.
connection
.
close
()
db
.
connection
.
close
()
location_mapper
=
loc_mapper
()
location_mapper
=
loc_mapper
()
if
location_mapper
.
db
:
if
location_mapper
.
db
:
location_mapper
.
location_map
.
drop
()
location_mapper
.
location_map
.
drop
()
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_locators.py
View file @
ca0dd839
...
@@ -200,13 +200,14 @@ class LocatorTest(TestCase):
...
@@ -200,13 +200,14 @@ class LocatorTest(TestCase):
expected_id
=
'mit.eecs.6002x'
expected_id
=
'mit.eecs.6002x'
expected_branch
=
'published'
expected_branch
=
'published'
expected_block_ref
=
'HW3'
expected_block_ref
=
'HW3'
testobj
=
BlockUsageLocator
(
package_id
=
testurn
)
testobj
=
BlockUsageLocator
(
url
=
testurn
)
self
.
check_block_locn_fields
(
testobj
,
'test_block constructor'
,
self
.
check_block_locn_fields
(
testobj
,
'test_block constructor'
,
package_id
=
expected_id
,
package_id
=
expected_id
,
branch
=
expected_branch
,
branch
=
expected_branch
,
block
=
expected_block_ref
)
block
=
expected_block_ref
)
self
.
assertEqual
(
str
(
testobj
),
testurn
)
self
.
assertEqual
(
str
(
testobj
),
testurn
)
self
.
assertEqual
(
testobj
.
url
(),
'edx://'
+
testurn
)
self
.
assertEqual
(
testobj
.
url
(),
'edx://'
+
testurn
)
testobj
=
BlockUsageLocator
(
url
=
testurn
,
version_guid
=
ObjectId
())
agnostic
=
testobj
.
version_agnostic
()
agnostic
=
testobj
.
version_agnostic
()
self
.
assertIsNone
(
agnostic
.
version_guid
)
self
.
assertIsNone
(
agnostic
.
version_guid
)
self
.
check_block_locn_fields
(
agnostic
,
'test_block constructor'
,
self
.
check_block_locn_fields
(
agnostic
,
'test_block constructor'
,
...
@@ -225,7 +226,7 @@ class LocatorTest(TestCase):
...
@@ -225,7 +226,7 @@ class LocatorTest(TestCase):
block
=
'lab2'
,
block
=
'lab2'
,
version_guid
=
ObjectId
(
test_id_loc
)
version_guid
=
ObjectId
(
test_id_loc
)
)
)
agnostic
=
testobj
.
version
_agnostic
()
agnostic
=
testobj
.
course
_agnostic
()
self
.
check_block_locn_fields
(
self
.
check_block_locn_fields
(
agnostic
,
'error parsing URL with version and block'
,
agnostic
,
'error parsing URL with version and block'
,
block
=
'lab2'
,
block
=
'lab2'
,
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
View file @
ca0dd839
import
pymongo
import
pymongo
from
uuid
import
uuid4
from
uuid
import
uuid4
import
copy
import
ddt
import
ddt
from
mock
import
patch
from
mock
import
patch
,
Mock
from
importlib
import
import_module
from
xmodule.tests
import
DATA_DIR
from
xmodule.tests
import
DATA_DIR
from
xmodule.modulestore
import
Location
,
MONGO_MODULESTORE_TYPE
,
SPLIT_MONGO_MODULESTORE_TYPE
,
\
from
xmodule.modulestore
import
Location
,
MONGO_MODULESTORE_TYPE
,
SPLIT_MONGO_MODULESTORE_TYPE
,
\
XML_MODULESTORE_TYPE
XML_MODULESTORE_TYPE
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.locator
import
BlockUsageLocator
from
xmodule.modulestore.locator
import
BlockUsageLocator
,
CourseLocator
from
xmodule.modulestore.tests.test_location_mapper
import
LocMapperSetupSansDjango
,
loc_mapper
from
xmodule.modulestore.tests.test_location_mapper
import
LocMapperSetupSansDjango
,
loc_mapper
# Mixed modulestore depends on django, so we'll manually configure some django settings
#
FIXME remove settings
#
before importing the module
from
django.conf
import
settings
from
django.conf
import
settings
if
not
settings
.
configured
:
if
not
settings
.
configured
:
settings
.
configure
()
settings
.
configure
()
from
xmodule.modulestore.mixed
import
MixedModuleStore
from
xmodule.modulestore.mixed
import
MixedModuleStore
@ddt.ddt
@ddt.ddt
class
TestMixedModuleStore
(
LocMapperSetupSansDjango
):
class
TestMixedModuleStore
(
LocMapperSetupSansDjango
):
"""
"""
...
@@ -32,7 +32,6 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -32,7 +32,6 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
FS_ROOT
=
DATA_DIR
FS_ROOT
=
DATA_DIR
DEFAULT_CLASS
=
'xmodule.raw_module.RawDescriptor'
DEFAULT_CLASS
=
'xmodule.raw_module.RawDescriptor'
RENDER_TEMPLATE
=
lambda
t_n
,
d
,
ctx
=
None
,
nsp
=
'main'
:
''
RENDER_TEMPLATE
=
lambda
t_n
,
d
,
ctx
=
None
,
nsp
=
'main'
:
''
REFERENCE_TYPE
=
'xmodule.modulestore.Location'
IMPORT_COURSEID
=
'MITx/999/2013_Spring'
IMPORT_COURSEID
=
'MITx/999/2013_Spring'
XML_COURSEID1
=
'edX/toy/2012_Fall'
XML_COURSEID1
=
'edX/toy/2012_Fall'
...
@@ -54,7 +53,6 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -54,7 +53,6 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
XML_COURSEID2
:
'xml'
,
XML_COURSEID2
:
'xml'
,
IMPORT_COURSEID
:
'default'
IMPORT_COURSEID
:
'default'
},
},
'reference_type'
:
REFERENCE_TYPE
,
'stores'
:
{
'stores'
:
{
'xml'
:
{
'xml'
:
{
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.xml.XMLModuleStore'
,
...
@@ -101,10 +99,13 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -101,10 +99,13 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
connection
.
drop_database
(
self
.
DB
)
self
.
connection
.
drop_database
(
self
.
DB
)
self
.
addCleanup
(
self
.
connection
.
drop_database
,
self
.
DB
)
self
.
addCleanup
(
self
.
connection
.
drop_database
,
self
.
DB
)
self
.
addCleanup
(
self
.
connection
.
close
)
self
.
addCleanup
(
self
.
connection
.
close
)
super
(
TestMixedModuleStore
,
self
)
.
setUp
()
super
(
TestMixedModuleStore
,
self
)
.
setUp
()
patcher
=
patch
(
'xmodule.modulestore.mixed.loc_mapper'
,
return_value
=
LocMapperSetupSansDjango
.
loc_store
)
patcher
=
patch
.
multiple
(
'xmodule.modulestore.mixed'
,
loc_mapper
=
Mock
(
return_value
=
LocMapperSetupSansDjango
.
loc_store
),
create_modulestore_instance
=
create_modulestore_instance
,
)
patcher
.
start
()
patcher
.
start
()
self
.
addCleanup
(
patcher
.
stop
)
self
.
addCleanup
(
patcher
.
stop
)
self
.
addTypeEqualityFunc
(
BlockUsageLocator
,
'_compareIgnoreVersion'
)
self
.
addTypeEqualityFunc
(
BlockUsageLocator
,
'_compareIgnoreVersion'
)
...
@@ -115,28 +116,26 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -115,28 +116,26 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
NOTE: course_location and item_location must be Location regardless of the app reference type in order
NOTE: course_location and item_location must be Location regardless of the app reference type in order
to cause the right mapping to be created.
to cause the right mapping to be created.
"""
"""
if
default
==
'split'
:
course
=
self
.
store
.
create_course
(
course
=
self
.
store
.
create_course
(
course_location
,
store_name
=
default
)
course_location
,
store_name
=
default
,
metadata
=
{
'display_name'
:
course_location
.
name
}
chapter
=
self
.
store
.
create_item
(
)
# don't use course_location as it may not be the repr
chapter
=
self
.
store
.
create_item
(
course
.
location
,
item_location
.
category
,
location
=
item_location
,
block_id
=
item_location
.
name
# don't use course_location as it may not be the repr
)
course
.
location
,
item_location
.
category
,
location
=
item_location
,
block_id
=
item_location
.
name
else
:
)
course
=
self
.
store
.
create_course
(
if
isinstance
(
course
.
location
,
CourseLocator
):
course_location
,
store_name
=
default
,
metadata
=
{
'display_name'
:
course_location
.
name
}
)
chapter
=
self
.
store
.
create_item
(
course_location
,
item_location
.
category
,
location
=
item_location
)
if
self
.
REFERENCE_TYPE
==
'xmodule.modulestore.locator.CourseLocator'
:
# add_entry is false b/c this is a test that the right thing happened w/o
# add_entry is false b/c this is a test that the right thing happened w/o
# wanting any additional side effects
# wanting any additional side effects
lookup_map
=
loc_mapper
()
.
translate_location
(
lookup_map
=
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
course_location
,
add_entry_if_missing
=
False
course_location
.
course_id
,
course_location
,
add_entry_if_missing
=
False
)
)
self
.
assertEqual
(
lookup_map
,
course
.
location
)
self
.
assertEqual
(
lookup_map
,
course
.
location
)
self
.
course_locations
[
self
.
IMPORT_COURSEID
]
=
course
.
location
.
version_agnostic
()
lookup_map
=
loc_mapper
()
.
translate_location
(
lookup_map
=
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
item_location
,
add_entry_if_missing
=
False
course_location
.
course_id
,
item_location
,
add_entry_if_missing
=
False
)
)
self
.
assertEqual
(
lookup_map
,
chapter
.
location
)
self
.
assertEqual
(
lookup_map
,
chapter
.
location
)
self
.
import_chapter_location
=
chapter
.
location
.
version_agnostic
()
else
:
else
:
self
.
assertEqual
(
course
.
location
,
course_location
)
self
.
assertEqual
(
course
.
location
,
course_location
)
self
.
assertEqual
(
chapter
.
location
,
item_location
)
self
.
assertEqual
(
chapter
.
location
,
item_location
)
...
@@ -154,8 +153,10 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -154,8 +153,10 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
"""
"""
Generate the locations for the given ids
Generate the locations for the given ids
"""
"""
org
,
course
,
run
=
course_id
.
split
(
'/'
)
course_dict
=
Location
.
parse_course_id
(
course_id
)
return
Location
(
'i4x'
,
org
,
course
,
'course'
,
run
)
course_dict
[
'tag'
]
=
'i4x'
course_dict
[
'category'
]
=
'course'
return
Location
(
course_dict
)
self
.
course_locations
=
{
self
.
course_locations
=
{
course_id
:
generate_location
(
course_id
)
course_id
:
generate_location
(
course_id
)
...
@@ -171,18 +172,8 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -171,18 +172,8 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
# grab old style location b4 possibly converted
# grab old style location b4 possibly converted
import_location
=
self
.
course_locations
[
self
.
IMPORT_COURSEID
]
import_location
=
self
.
course_locations
[
self
.
IMPORT_COURSEID
]
# get Locators and set up the loc mapper if app is Locator based
# get Locators and set up the loc mapper if app is Locator based
if
self
.
REFERENCE_TYPE
==
'xmodule.modulestore.locator.CourseLocator
'
:
if
default
==
'split
'
:
self
.
fake_location
=
loc_mapper
()
.
translate_location
(
'foo/bar/2012_Fall'
,
self
.
fake_location
)
self
.
fake_location
=
loc_mapper
()
.
translate_location
(
'foo/bar/2012_Fall'
,
self
.
fake_location
)
self
.
import_chapter_location
=
loc_mapper
()
.
translate_location
(
self
.
IMPORT_COURSEID
,
self
.
import_chapter_location
)
self
.
xml_chapter_location
=
loc_mapper
()
.
translate_location
(
self
.
XML_COURSEID1
,
self
.
xml_chapter_location
)
self
.
course_locations
=
{
course_id
:
loc_mapper
()
.
translate_location
(
course_id
,
locn
)
for
course_id
,
locn
in
self
.
course_locations
.
iteritems
()
}
self
.
_create_course
(
default
,
import_location
,
self
.
import_chapter_location
)
self
.
_create_course
(
default
,
import_location
,
self
.
import_chapter_location
)
...
@@ -206,8 +197,11 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -206,8 +197,11 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
assertTrue
(
self
.
store
.
has_item
(
course_id
,
course_locn
))
self
.
assertTrue
(
self
.
store
.
has_item
(
course_id
,
course_locn
))
# try negative cases
# try negative cases
self
.
assertFalse
(
self
.
store
.
has_item
(
self
.
XML_COURSEID1
,
self
.
course_locations
[
self
.
IMPORT_COURSEID
]))
self
.
assertFalse
(
self
.
store
.
has_item
(
self
.
assertFalse
(
self
.
store
.
has_item
(
self
.
IMPORT_COURSEID
,
self
.
course_locations
[
self
.
XML_COURSEID1
]))
self
.
XML_COURSEID1
,
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
replace
(
name
=
'not_findable'
,
category
=
'problem'
)
))
self
.
assertFalse
(
self
.
store
.
has_item
(
self
.
IMPORT_COURSEID
,
self
.
fake_location
))
@ddt.data
(
'direct'
,
'split'
)
@ddt.data
(
'direct'
,
'split'
)
def
test_get_item
(
self
,
default_ms
):
def
test_get_item
(
self
,
default_ms
):
...
@@ -223,9 +217,12 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -223,9 +217,12 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
# try negative cases
# try negative cases
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_instance
(
self
.
XML_COURSEID1
,
self
.
course_locations
[
self
.
IMPORT_COURSEID
])
self
.
store
.
get_instance
(
self
.
XML_COURSEID1
,
self
.
course_locations
[
self
.
XML_COURSEID1
]
.
replace
(
name
=
'not_findable'
,
category
=
'problem'
)
)
with
self
.
assertRaises
(
ItemNotFoundError
):
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_instance
(
self
.
IMPORT_COURSEID
,
self
.
course_locations
[
self
.
XML_COURSEID1
]
)
self
.
store
.
get_instance
(
self
.
IMPORT_COURSEID
,
self
.
fake_location
)
@ddt.data
(
'direct'
,
'split'
)
@ddt.data
(
'direct'
,
'split'
)
def
test_get_items
(
self
,
default_ms
):
def
test_get_items
(
self
,
default_ms
):
...
@@ -246,11 +243,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -246,11 +243,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
Update should fail for r/o dbs and succeed for r/w ones
Update should fail for r/o dbs and succeed for r/w ones
"""
"""
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
# try a r/o db
course_id
=
self
.
XML_COURSEID1
if
self
.
REFERENCE_TYPE
==
'xmodule.modulestore.locator.CourseLocator'
:
course_id
=
self
.
course_locations
[
self
.
XML_COURSEID1
]
else
:
course_id
=
self
.
XML_COURSEID1
course
=
self
.
store
.
get_course
(
course_id
)
course
=
self
.
store
.
get_course
(
course_id
)
# if following raised, then the test is really a noop, change it
# if following raised, then the test is really a noop, change it
self
.
assertFalse
(
course
.
show_calculator
,
"Default changed making test meaningless"
)
self
.
assertFalse
(
course
.
show_calculator
,
"Default changed making test meaningless"
)
...
@@ -288,10 +281,14 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -288,10 +281,14 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
@ddt.data
(
'direct'
,
'split'
)
@ddt.data
(
'direct'
,
'split'
)
def
test_get_courses
(
self
,
default_ms
):
def
test_get_courses
(
self
,
default_ms
):
self
.
initdb
(
default_ms
)
self
.
initdb
(
default_ms
)
# we should have 3 total courses a
ggregated
# we should have 3 total courses a
cross all stores
courses
=
self
.
store
.
get_courses
()
courses
=
self
.
store
.
get_courses
()
self
.
assertEqual
(
len
(
courses
),
3
)
self
.
assertEqual
(
len
(
courses
),
3
)
course_ids
=
[
course
.
location
for
course
in
courses
]
course_ids
=
[
course
.
location
.
version_agnostic
()
if
hasattr
(
course
.
location
,
'version_agnostic'
)
else
course
.
location
for
course
in
courses
]
self
.
assertIn
(
self
.
course_locations
[
self
.
IMPORT_COURSEID
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
IMPORT_COURSEID
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
XML_COURSEID1
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
XML_COURSEID1
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
XML_COURSEID2
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
XML_COURSEID2
],
course_ids
)
...
@@ -300,6 +297,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -300,6 +297,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
"""
"""
Test that the xml modulestore only loaded the courses from the maps.
Test that the xml modulestore only loaded the courses from the maps.
"""
"""
self
.
initdb
(
'direct'
)
courses
=
self
.
store
.
modulestores
[
'xml'
]
.
get_courses
()
courses
=
self
.
store
.
modulestores
[
'xml'
]
.
get_courses
()
self
.
assertEqual
(
len
(
courses
),
2
)
self
.
assertEqual
(
len
(
courses
),
2
)
course_ids
=
[
course
.
location
.
course_id
for
course
in
courses
]
course_ids
=
[
course
.
location
.
course_id
for
course
in
courses
]
...
@@ -339,33 +337,28 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
...
@@ -339,33 +337,28 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
assertEqual
(
len
(
parents
),
1
)
self
.
assertEqual
(
len
(
parents
),
1
)
self
.
assertEqual
(
parents
[
0
],
self
.
course_locations
[
self
.
XML_COURSEID1
])
self
.
assertEqual
(
parents
[
0
],
self
.
course_locations
[
self
.
XML_COURSEID1
])
@ddt.ddt
#=============================================================================================================
class
TestMixedUseLocator
(
TestMixedModuleStore
):
# General utils for not using django settings
#=============================================================================================================
def
load_function
(
path
):
"""
"""
Tests a mixed ms which uses Locators instead of Locations
Load a function by name.
path is a string of the form "path.to.module.function"
returns the imported python object `function` from `path.to.module`
"""
"""
REFERENCE_TYPE
=
'xmodule.modulestore.locator.CourseLocator'
module_path
,
_
,
name
=
path
.
rpartition
(
'.'
)
return
getattr
(
import_module
(
module_path
),
name
)
def
setUp
(
self
):
self
.
options
=
copy
.
copy
(
self
.
OPTIONS
)
self
.
options
[
'reference_type'
]
=
self
.
REFERENCE_TYPE
super
(
TestMixedUseLocator
,
self
)
.
setUp
()
@ddt.ddt
def
create_modulestore_instance
(
engine
,
doc_store_config
,
options
,
i18n_service
=
None
):
class
TestMixedMSInit
(
TestMixedModuleStore
):
"""
"""
T
est initializing w/o a reference_type
T
his will return a new instance of a modulestore given an engine and options
"""
"""
REFERENCE_TYPE
=
None
class_
=
load_function
(
engine
)
def
setUp
(
self
):
self
.
options
=
copy
.
copy
(
self
.
OPTIONS
)
del
self
.
options
[
'reference_type'
]
super
(
TestMixedMSInit
,
self
)
.
setUp
()
@ddt.data
(
'direct'
,
'split'
)
return
class_
(
def
test_use_locations
(
self
,
default_ms
):
doc_store_config
=
doc_store_config
,
"""
**
options
Test that use_locations defaulted correctly
)
"""
self
.
initdb
(
default_ms
)
self
.
assertEqual
(
self
.
store
.
reference_type
,
Location
)
lms/envs/acceptance.py
View file @
ca0dd839
...
@@ -45,7 +45,6 @@ MODULESTORE = {
...
@@ -45,7 +45,6 @@ MODULESTORE = {
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'OPTIONS'
:
{
'OPTIONS'
:
{
'mappings'
:
{},
'mappings'
:
{},
'reference_type'
:
'xmodule.modulestore.Location'
,
'stores'
:
{
'stores'
:
{
'default'
:
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.mongo.MongoModuleStore'
,
...
...
lms/envs/cms/dev.py
View file @
ca0dd839
...
@@ -32,7 +32,6 @@ MODULESTORE = {
...
@@ -32,7 +32,6 @@ MODULESTORE = {
'default'
:
{
'default'
:
{
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'ENGINE'
:
'xmodule.modulestore.mixed.MixedModuleStore'
,
'OPTIONS'
:
{
'OPTIONS'
:
{
'reference_type'
:
'Location'
,
'mappings'
:
{},
'mappings'
:
{},
'stores'
:
{
'stores'
:
{
'default'
:
{
'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