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
41f88344
Commit
41f88344
authored
Jan 15, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2167 from edx/dhm/split_block_id
Encode periods and $ in block_id map
parents
80d54afd
13a04927
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
116 additions
and
48 deletions
+116
-48
common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py
+8
-6
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
+4
-1
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+76
-41
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
+28
-0
No files found.
common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py
View file @
41f88344
...
@@ -156,7 +156,7 @@ class LocMapperStore(object):
...
@@ -156,7 +156,7 @@ class LocMapperStore(object):
entry
=
item
entry
=
item
break
break
block_id
=
entry
[
'block_map'
]
.
get
(
self
.
_encode
_for_mongo
(
location
.
name
))
block_id
=
entry
[
'block_map'
]
.
get
(
self
.
encode_key
_for_mongo
(
location
.
name
))
if
block_id
is
None
:
if
block_id
is
None
:
if
add_entry_if_missing
:
if
add_entry_if_missing
:
block_id
=
self
.
_add_to_block_map
(
location
,
location_id
,
entry
[
'block_map'
])
block_id
=
self
.
_add_to_block_map
(
location
,
location_id
,
entry
[
'block_map'
])
...
@@ -231,7 +231,7 @@ class LocMapperStore(object):
...
@@ -231,7 +231,7 @@ class LocMapperStore(object):
candidate
[
'_id'
][
'org'
],
candidate
[
'_id'
][
'org'
],
candidate
[
'_id'
][
'course'
],
candidate
[
'_id'
][
'course'
],
category
,
category
,
self
.
_decode
_from_mongo
(
old_name
),
self
.
decode_key
_from_mongo
(
old_name
),
None
)
None
)
published_locator
=
BlockUsageLocator
(
published_locator
=
BlockUsageLocator
(
candidate
[
'course_id'
],
branch
=
candidate
[
'prod_branch'
],
block_id
=
block_id
candidate
[
'course_id'
],
branch
=
candidate
[
'prod_branch'
],
block_id
=
block_id
...
@@ -261,7 +261,7 @@ class LocMapperStore(object):
...
@@ -261,7 +261,7 @@ class LocMapperStore(object):
# if 2 different category locations had same name, then they'll collide. Make the later
# if 2 different category locations had same name, then they'll collide. Make the later
# mapped ones unique
# mapped ones unique
block_id
=
self
.
_verify_uniqueness
(
location
.
name
,
block_map
)
block_id
=
self
.
_verify_uniqueness
(
location
.
name
,
block_map
)
encoded_location_name
=
self
.
_encode
_for_mongo
(
location
.
name
)
encoded_location_name
=
self
.
encode_key
_for_mongo
(
location
.
name
)
block_map
.
setdefault
(
encoded_location_name
,
{})[
location
.
category
]
=
block_id
block_map
.
setdefault
(
encoded_location_name
,
{})[
location
.
category
]
=
block_id
self
.
location_map
.
update
(
location_id
,
{
'$set'
:
{
'block_map'
:
block_map
}})
self
.
location_map
.
update
(
location_id
,
{
'$set'
:
{
'block_map'
:
block_map
}})
return
block_id
return
block_id
...
@@ -331,7 +331,8 @@ class LocMapperStore(object):
...
@@ -331,7 +331,8 @@ class LocMapperStore(object):
return
self
.
_verify_uniqueness
(
name
,
block_map
)
return
self
.
_verify_uniqueness
(
name
,
block_map
)
return
name
return
name
def
_encode_for_mongo
(
self
,
fieldname
):
@staticmethod
def
encode_key_for_mongo
(
fieldname
):
"""
"""
Fieldnames in mongo cannot have periods nor dollar signs. So encode them.
Fieldnames in mongo cannot have periods nor dollar signs. So encode them.
:param fieldname: an atomic field name. Note, don't pass structured paths as it will flatten them
:param fieldname: an atomic field name. Note, don't pass structured paths as it will flatten them
...
@@ -340,9 +341,10 @@ class LocMapperStore(object):
...
@@ -340,9 +341,10 @@ class LocMapperStore(object):
fieldname
=
fieldname
.
replace
(
char
,
'
%
{:02x}'
.
format
(
ord
(
char
)))
fieldname
=
fieldname
.
replace
(
char
,
'
%
{:02x}'
.
format
(
ord
(
char
)))
return
fieldname
return
fieldname
def
_decode_from_mongo
(
self
,
fieldname
):
@staticmethod
def
decode_key_from_mongo
(
fieldname
):
"""
"""
The inverse of
_encode
_for_mongo
The inverse of
encode_key
_for_mongo
:param fieldname: with period and dollar escaped
:param fieldname: with period and dollar escaped
"""
"""
return
urllib
.
unquote
(
fieldname
)
return
urllib
.
unquote
(
fieldname
)
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
View file @
41f88344
...
@@ -8,6 +8,7 @@ from xblock.runtime import KvsFieldData, IdReader
...
@@ -8,6 +8,7 @@ from xblock.runtime import KvsFieldData, IdReader
from
..exceptions
import
ItemNotFoundError
from
..exceptions
import
ItemNotFoundError
from
.split_mongo_kvs
import
SplitMongoKVS
from
.split_mongo_kvs
import
SplitMongoKVS
from
xblock.fields
import
ScopeIds
from
xblock.fields
import
ScopeIds
from
xmodule.modulestore.loc_mapper_store
import
LocMapperStore
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -63,7 +64,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
...
@@ -63,7 +64,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
# Compute inheritance
# Compute inheritance
modulestore
.
inherit_settings
(
modulestore
.
inherit_settings
(
course_entry
[
'structure'
]
.
get
(
'blocks'
,
{}),
course_entry
[
'structure'
]
.
get
(
'blocks'
,
{}),
course_entry
[
'structure'
]
.
get
(
'blocks'
,
{})
.
get
(
course_entry
[
'structure'
]
.
get
(
'root'
))
course_entry
[
'structure'
]
.
get
(
'blocks'
,
{})
.
get
(
LocMapperStore
.
encode_key_for_mongo
(
course_entry
[
'structure'
]
.
get
(
'root'
))
)
)
)
self
.
default_class
=
default_class
self
.
default_class
=
default_class
self
.
local_modules
=
{}
self
.
local_modules
=
{}
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
41f88344
...
@@ -56,7 +56,7 @@ import copy
...
@@ -56,7 +56,7 @@ import copy
from
pytz
import
UTC
from
pytz
import
UTC
from
xmodule.errortracker
import
null_error_tracker
from
xmodule.errortracker
import
null_error_tracker
from
xmodule.x_module
import
XModuleDescriptor
,
prefer_xmodules
from
xmodule.x_module
import
prefer_xmodules
from
xmodule.modulestore.locator
import
BlockUsageLocator
,
DefinitionLocator
,
CourseLocator
,
VersionTree
,
LocalId
from
xmodule.modulestore.locator
import
BlockUsageLocator
,
DefinitionLocator
,
CourseLocator
,
VersionTree
,
LocalId
from
xmodule.modulestore.exceptions
import
InsufficientSpecificationError
,
VersionConflictError
,
DuplicateItemError
from
xmodule.modulestore.exceptions
import
InsufficientSpecificationError
,
VersionConflictError
,
DuplicateItemError
from
xmodule.modulestore
import
inheritance
,
ModuleStoreWriteBase
,
Location
,
SPLIT_MONGO_MODULESTORE_TYPE
from
xmodule.modulestore
import
inheritance
,
ModuleStoreWriteBase
,
Location
,
SPLIT_MONGO_MODULESTORE_TYPE
...
@@ -69,6 +69,7 @@ from xblock.runtime import Mixologist
...
@@ -69,6 +69,7 @@ from xblock.runtime import Mixologist
from
bson.objectid
import
ObjectId
from
bson.objectid
import
ObjectId
from
xmodule.modulestore.split_mongo.mongo_connection
import
MongoConnection
from
xmodule.modulestore.split_mongo.mongo_connection
import
MongoConnection
from
xblock.core
import
XBlock
from
xblock.core
import
XBlock
from
xmodule.modulestore.loc_mapper_store
import
LocMapperStore
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
#==============================================================================
#==============================================================================
...
@@ -343,7 +344,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -343,7 +344,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# this error only occurs if the course does not exist
# this error only occurs if the course does not exist
return
False
return
False
return
course_structure
[
'blocks'
]
.
get
(
block_location
.
block_id
)
is
not
None
return
self
.
_get_block_from_structure
(
course_structure
,
block_location
.
block_id
)
is
not
None
def
get_item
(
self
,
location
,
depth
=
0
):
def
get_item
(
self
,
location
,
depth
=
0
):
"""
"""
...
@@ -432,7 +433,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -432,7 +433,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'''
'''
course
=
self
.
_lookup_course
(
locator
)
course
=
self
.
_lookup_course
(
locator
)
items
=
self
.
_get_parents_from_structure
(
locator
.
block_id
,
course
[
'structure'
])
items
=
self
.
_get_parents_from_structure
(
locator
.
block_id
,
course
[
'structure'
])
return
[
BlockUsageLocator
(
url
=
locator
.
as_course_locator
(),
block_id
=
parent_id
)
return
[
BlockUsageLocator
(
url
=
locator
.
as_course_locator
(),
block_id
=
LocMapperStore
.
decode_key_from_mongo
(
parent_id
),
)
for
parent_id
in
items
]
for
parent_id
in
items
]
def
get_orphans
(
self
,
package_id
,
detached_categories
,
branch
):
def
get_orphans
(
self
,
package_id
,
detached_categories
,
branch
):
...
@@ -442,12 +446,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -442,12 +446,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param package_id:
:param package_id:
"""
"""
course
=
self
.
_lookup_course
(
CourseLocator
(
package_id
=
package_id
,
branch
=
branch
))
course
=
self
.
_lookup_course
(
CourseLocator
(
package_id
=
package_id
,
branch
=
branch
))
items
=
set
(
course
[
'structure'
][
'blocks'
]
.
keys
())
items
=
{
LocMapperStore
.
decode_key_from_mongo
(
block_id
)
for
block_id
in
course
[
'structure'
][
'blocks'
]
.
keys
()}
items
.
remove
(
course
[
'structure'
][
'root'
])
items
.
remove
(
course
[
'structure'
][
'root'
])
for
block_id
,
block_data
in
course
[
'structure'
][
'blocks'
]
.
iteritems
():
for
block_id
,
block_data
in
course
[
'structure'
][
'blocks'
]
.
iteritems
():
items
.
difference_update
(
block_data
.
get
(
'fields'
,
{})
.
get
(
'children'
,
[]))
items
.
difference_update
(
block_data
.
get
(
'fields'
,
{})
.
get
(
'children'
,
[]))
if
block_data
[
'category'
]
in
detached_categories
:
if
block_data
[
'category'
]
in
detached_categories
:
items
.
discard
(
block_id
)
items
.
discard
(
LocMapperStore
.
decode_key_from_mongo
(
block_id
)
)
return
[
return
[
BlockUsageLocator
(
package_id
=
package_id
,
branch
=
branch
,
block_id
=
block_id
)
BlockUsageLocator
(
package_id
=
package_id
,
branch
=
branch
,
block_id
=
block_id
)
for
block_id
in
items
for
block_id
in
items
...
@@ -554,21 +558,22 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -554,21 +558,22 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
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'
],
update_version_field
:
{
'$exists'
:
True
}})
update_version_field
:
{
'$exists'
:
True
}})
# find (all) root versions and build map
previous: [successors]
# find (all) root versions and build map
{previous: {successors}..}
possible_roots
=
[]
possible_roots
=
[]
result
=
{}
result
=
{}
for
version
in
all_versions_with_block
:
for
version
in
all_versions_with_block
:
if
version
[
'_id'
]
==
version
[
'blocks'
][
block_id
][
'edit_info'
][
'update_version'
]:
block_payload
=
self
.
_get_block_from_structure
(
version
,
block_id
)
if
version
[
'blocks'
][
block_id
][
'edit_info'
]
.
get
(
'previous_version'
)
is
None
:
if
version
[
'_id'
]
==
block_payload
[
'edit_info'
][
'update_version'
]:
possible_roots
.
append
(
version
[
'blocks'
][
block_id
][
'edit_info'
][
'update_version'
])
if
block_payload
[
'edit_info'
]
.
get
(
'previous_version'
)
is
None
:
else
:
possible_roots
.
append
(
block_payload
[
'edit_info'
][
'update_version'
])
result
.
setdefault
(
version
[
'blocks'
][
block_id
][
'edit_info'
][
'previous_version'
],
set
())
.
add
(
else
:
# map previous to {update..}
version
[
'blocks'
][
block_id
][
'edit_info'
][
'update_version'
])
result
.
setdefault
(
block_payload
[
'edit_info'
][
'previous_version'
],
set
())
.
add
(
block_payload
[
'edit_info'
][
'update_version'
])
# more than one possible_root means usage was added and deleted > 1x.
# more than one possible_root means usage was added and deleted > 1x.
if
len
(
possible_roots
)
>
1
:
if
len
(
possible_roots
)
>
1
:
# find the history segment including block_locator's version
# find the history segment including block_locator's version
element_to_find
=
course_struct
[
'blocks'
][
block_id
]
[
'edit_info'
][
'update_version'
]
element_to_find
=
self
.
_get_block_from_structure
(
course_struct
,
block_id
)
[
'edit_info'
][
'update_version'
]
if
element_to_find
in
possible_roots
:
if
element_to_find
in
possible_roots
:
possible_roots
=
[
element_to_find
]
possible_roots
=
[
element_to_find
]
for
possibility
in
possible_roots
:
for
possibility
in
possible_roots
:
...
@@ -660,6 +665,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -660,6 +665,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# {category: last_serial...}
# {category: last_serial...}
# A potential confusion is if the name incorporates the parent's name, then if the child
# A potential confusion is if the name incorporates the parent's name, then if the child
# moves, its id won't change and will be confusing
# moves, its id won't change and will be confusing
# NOTE2: this assumes category will never contain a $ nor a period.
serial
=
1
serial
=
1
while
category
+
str
(
serial
)
in
course_blocks
:
while
category
+
str
(
serial
)
in
course_blocks
:
serial
+=
1
serial
+=
1
...
@@ -760,7 +766,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -760,7 +766,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# generate usage id
# generate usage id
if
block_id
is
not
None
:
if
block_id
is
not
None
:
if
block_id
in
new_structure
[
'blocks'
]:
if
LocMapperStore
.
encode_key_for_mongo
(
block_id
)
in
new_structure
[
'blocks'
]:
raise
DuplicateItemError
(
block_id
,
self
,
'structures'
)
raise
DuplicateItemError
(
block_id
,
self
,
'structures'
)
else
:
else
:
new_block_id
=
block_id
new_block_id
=
block_id
...
@@ -770,7 +776,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -770,7 +776,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block_fields
=
partitioned_fields
.
get
(
Scope
.
settings
,
{})
block_fields
=
partitioned_fields
.
get
(
Scope
.
settings
,
{})
if
Scope
.
children
in
partitioned_fields
:
if
Scope
.
children
in
partitioned_fields
:
block_fields
.
update
(
partitioned_fields
[
Scope
.
children
])
block_fields
.
update
(
partitioned_fields
[
Scope
.
children
])
new_structure
[
'blocks'
][
new_block_id
]
=
{
self
.
_update_block_in_structure
(
new_structure
,
new_block_id
,
{
"category"
:
category
,
"category"
:
category
,
"definition"
:
definition_locator
.
definition_id
,
"definition"
:
definition_locator
.
definition_id
,
"fields"
:
block_fields
,
"fields"
:
block_fields
,
...
@@ -780,12 +786,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -780,12 +786,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'previous_version'
:
None
,
'previous_version'
:
None
,
'update_version'
:
new_id
,
'update_version'
:
new_id
,
}
}
}
}
)
# if given parent, add new block as child and update parent's version
# if given parent, add new block as child and update parent's version
parent
=
None
parent
=
None
if
isinstance
(
course_or_parent_locator
,
BlockUsageLocator
)
and
course_or_parent_locator
.
block_id
is
not
None
:
if
isinstance
(
course_or_parent_locator
,
BlockUsageLocator
)
and
course_or_parent_locator
.
block_id
is
not
None
:
parent
=
new_structure
[
'blocks'
][
course_or_parent_locator
.
block_id
]
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
course_or_parent_locator
.
block_id
)
parent
=
new_structure
[
'blocks'
][
encoded_block_id
]
parent
[
'fields'
]
.
setdefault
(
'children'
,
[])
.
append
(
new_block_id
)
parent
[
'fields'
]
.
setdefault
(
'children'
,
[])
.
append
(
new_block_id
)
if
not
continue_version
or
parent
[
'edit_info'
][
'update_version'
]
!=
structure
[
'_id'
]:
if
not
continue_version
or
parent
[
'edit_info'
][
'update_version'
]
!=
structure
[
'_id'
]:
parent
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
parent
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
...
@@ -892,7 +899,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -892,7 +899,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if
definition_fields
or
block_fields
:
if
definition_fields
or
block_fields
:
draft_structure
=
self
.
_version_structure
(
draft_structure
,
user_id
)
draft_structure
=
self
.
_version_structure
(
draft_structure
,
user_id
)
new_id
=
draft_structure
[
'_id'
]
new_id
=
draft_structure
[
'_id'
]
root_block
=
draft_structure
[
'blocks'
][
draft_structure
[
'root'
]]
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
draft_structure
[
'root'
])
root_block
=
draft_structure
[
'blocks'
][
encoded_block_id
]
if
block_fields
is
not
None
:
if
block_fields
is
not
None
:
root_block
[
'fields'
]
.
update
(
block_fields
)
root_block
[
'fields'
]
.
update
(
block_fields
)
if
definition_fields
is
not
None
:
if
definition_fields
is
not
None
:
...
@@ -948,7 +956,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -948,7 +956,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
descriptor
.
definition_locator
,
is_updated
=
self
.
update_definition_from_data
(
descriptor
.
definition_locator
,
is_updated
=
self
.
update_definition_from_data
(
descriptor
.
definition_locator
,
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
),
user_id
)
descriptor
.
definition_locator
,
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
),
user_id
)
# check children
# check children
original_entry
=
original_structure
[
'blocks'
][
descriptor
.
location
.
block_id
]
original_entry
=
self
.
_get_block_from_structure
(
original_structure
,
descriptor
.
location
.
block_id
)
is_updated
=
is_updated
or
(
is_updated
=
is_updated
or
(
descriptor
.
has_children
and
original_entry
[
'fields'
][
'children'
]
!=
descriptor
.
children
descriptor
.
has_children
and
original_entry
[
'fields'
][
'children'
]
!=
descriptor
.
children
)
)
...
@@ -962,7 +970,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -962,7 +970,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# if updated, rev the structure
# if updated, rev the structure
if
is_updated
:
if
is_updated
:
new_structure
=
self
.
_version_structure
(
original_structure
,
user_id
)
new_structure
=
self
.
_version_structure
(
original_structure
,
user_id
)
block_data
=
new_structure
[
'blocks'
][
descriptor
.
location
.
block_id
]
block_data
=
self
.
_get_block_from_structure
(
new_structure
,
descriptor
.
location
.
block_id
)
block_data
[
"definition"
]
=
descriptor
.
definition_locator
.
definition_id
block_data
[
"definition"
]
=
descriptor
.
definition_locator
.
definition_id
block_data
[
"fields"
]
=
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
block_data
[
"fields"
]
=
descriptor
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
...
@@ -1048,12 +1056,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1048,12 +1056,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
is_new
=
True
is_new
=
True
is_updated
=
True
is_updated
=
True
block_id
=
self
.
_generate_block_id
(
structure_blocks
,
xblock
.
category
)
block_id
=
self
.
_generate_block_id
(
structure_blocks
,
xblock
.
category
)
encoded_block_id
=
block_id
xblock
.
scope_ids
.
usage_id
.
block_id
=
block_id
xblock
.
scope_ids
.
usage_id
.
block_id
=
block_id
else
:
else
:
is_new
=
False
is_new
=
False
block_id
=
xblock
.
location
.
block_id
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
xblock
.
location
.
block_id
)
is_updated
=
is_updated
or
(
is_updated
=
is_updated
or
(
xblock
.
has_children
and
structure_blocks
[
block_id
][
'fields'
][
'children'
]
!=
xblock
.
children
xblock
.
has_children
and
structure_blocks
[
encoded_
block_id
][
'fields'
][
'children'
]
!=
xblock
.
children
)
)
children
=
[]
children
=
[]
...
@@ -1068,13 +1077,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1068,13 +1077,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block_fields
=
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
block_fields
=
xblock
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
if
not
is_new
and
not
is_updated
:
if
not
is_new
and
not
is_updated
:
is_updated
=
self
.
_compare_settings
(
block_fields
,
structure_blocks
[
block_id
][
'fields'
])
is_updated
=
self
.
_compare_settings
(
block_fields
,
structure_blocks
[
encoded_
block_id
][
'fields'
])
if
children
:
if
children
:
block_fields
[
'children'
]
=
children
block_fields
[
'children'
]
=
children
if
is_updated
:
if
is_updated
:
previous_version
=
None
if
is_new
else
structure_blocks
[
block_id
][
'edit_info'
]
.
get
(
'update_version'
)
previous_version
=
None
if
is_new
else
structure_blocks
[
encoded_
block_id
][
'edit_info'
]
.
get
(
'update_version'
)
structure_blocks
[
block_id
]
=
{
structure_blocks
[
encoded_
block_id
]
=
{
"category"
:
xblock
.
category
,
"category"
:
xblock
.
category
,
"definition"
:
xblock
.
definition_locator
.
definition_id
,
"definition"
:
xblock
.
definition_locator
.
definition_id
,
"fields"
:
block_fields
,
"fields"
:
block_fields
,
...
@@ -1226,7 +1235,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1226,7 +1235,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
new_id
=
new_structure
[
'_id'
]
new_id
=
new_structure
[
'_id'
]
parents
=
self
.
get_parent_locations
(
usage_locator
)
parents
=
self
.
get_parent_locations
(
usage_locator
)
for
parent
in
parents
:
for
parent
in
parents
:
parent_block
=
new_blocks
[
parent
.
block_id
]
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
parent
.
block_id
)
parent_block
=
new_blocks
[
encoded_block_id
]
parent_block
[
'fields'
][
'children'
]
.
remove
(
usage_locator
.
block_id
)
parent_block
[
'fields'
][
'children'
]
.
remove
(
usage_locator
.
block_id
)
parent_block
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
parent_block
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
parent_block
[
'edit_info'
][
'edited_by'
]
=
user_id
parent_block
[
'edit_info'
][
'edited_by'
]
=
user_id
...
@@ -1237,13 +1247,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1237,13 +1247,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
"""
Remove the subtree rooted at block_id
Remove the subtree rooted at block_id
"""
"""
for
child
in
new_blocks
[
block_id
][
'fields'
]
.
get
(
'children'
,
[]):
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
block_id
)
for
child
in
new_blocks
[
encoded_block_id
][
'fields'
]
.
get
(
'children'
,
[]):
remove_subtree
(
child
)
remove_subtree
(
child
)
del
new_blocks
[
block_id
]
del
new_blocks
[
encoded_
block_id
]
if
delete_children
:
if
delete_children
:
remove_subtree
(
usage_locator
.
block_id
)
remove_subtree
(
usage_locator
.
block_id
)
else
:
else
:
del
new_blocks
[
usage_locator
.
block_id
]
del
new_blocks
[
LocMapperStore
.
encode_key_for_mongo
(
usage_locator
.
block_id
)
]
# update index if appropriate and structures
# update index if appropriate and structures
self
.
db_connection
.
insert_structure
(
new_structure
)
self
.
db_connection
.
insert_structure
(
new_structure
)
...
@@ -1306,6 +1317,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1306,6 +1317,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
for
child
in
block_fields
.
get
(
'children'
,
[]):
for
child
in
block_fields
.
get
(
'children'
,
[]):
try
:
try
:
child
=
LocMapperStore
.
encode_key_for_mongo
(
child
)
self
.
inherit_settings
(
block_map
,
block_map
[
child
],
inheriting_settings
)
self
.
inherit_settings
(
block_map
,
block_map
[
child
],
inheriting_settings
)
except
KeyError
:
except
KeyError
:
# here's where we need logic for looking up in other structures when we allow cross pointers
# here's where we need logic for looking up in other structures when we allow cross pointers
...
@@ -1320,16 +1332,18 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1320,16 +1332,18 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
(0 => this usage only, 1 => this usage and its children, etc...)
(0 => this usage only, 1 => this usage and its children, etc...)
A depth of None returns all descendants
A depth of None returns all descendants
"""
"""
if
block_id
not
in
block_map
:
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
block_id
)
if
encoded_block_id
not
in
block_map
:
return
descendent_map
return
descendent_map
if
block_id
not
in
descendent_map
:
if
block_id
not
in
descendent_map
:
descendent_map
[
block_id
]
=
block_map
[
block_id
]
descendent_map
[
block_id
]
=
block_map
[
encoded_
block_id
]
if
depth
is
None
or
depth
>
0
:
if
depth
is
None
or
depth
>
0
:
depth
=
depth
-
1
if
depth
is
not
None
else
None
depth
=
depth
-
1
if
depth
is
not
None
else
None
for
child
in
block_map
[
block_id
][
'fields'
]
.
get
(
'children'
,
[]):
for
child
in
descendent_map
[
block_id
][
'fields'
]
.
get
(
'children'
,
[]):
descendent_map
=
self
.
descendants
(
block_map
,
child
,
depth
,
descendent_map
)
descendent_map
=
self
.
descendants
(
block_map
,
child
,
depth
,
descendent_map
)
return
descendent_map
return
descendent_map
...
@@ -1357,7 +1371,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1357,7 +1371,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
for
block
in
original_structure
[
'blocks'
]
.
itervalues
():
for
block
in
original_structure
[
'blocks'
]
.
itervalues
():
if
'fields'
in
block
and
'children'
in
block
[
'fields'
]:
if
'fields'
in
block
and
'children'
in
block
[
'fields'
]:
block
[
'fields'
][
"children"
]
=
[
block
[
'fields'
][
"children"
]
=
[
block_id
for
block_id
in
block
[
'fields'
][
"children"
]
if
block_id
in
original_structure
[
'blocks'
]
block_id
for
block_id
in
block
[
'fields'
][
"children"
]
if
LocMapperStore
.
encode_key_for_mongo
(
block_id
)
in
original_structure
[
'blocks'
]
]
]
self
.
db_connection
.
update_structure
(
original_structure
)
self
.
db_connection
.
update_structure
(
original_structure
)
# clear cache again b/c inheritance may be wrong over orphans
# clear cache again b/c inheritance may be wrong over orphans
...
@@ -1511,8 +1526,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1511,8 +1526,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
"""
new_id
=
ObjectId
()
new_id
=
ObjectId
()
if
root_category
is
not
None
:
if
root_category
is
not
None
:
encoded_root
=
LocMapperStore
.
encode_key_for_mongo
(
root_block_id
)
blocks
=
{
blocks
=
{
root_block_id
:
self
.
_new_block
(
user_id
,
root_category
,
block_fields
,
definition_id
,
new_id
)
encoded_root
:
self
.
_new_block
(
user_id
,
root_category
,
block_fields
,
definition_id
,
new_id
)
}
}
else
:
else
:
blocks
=
{}
blocks
=
{}
...
@@ -1528,7 +1546,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1528,7 +1546,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
def
_get_parents_from_structure
(
self
,
block_id
,
structure
):
def
_get_parents_from_structure
(
self
,
block_id
,
structure
):
"""
"""
Given a structure, find all of block_id's parents in that structure
Given a structure, find all of block_id's parents in that structure. Note returns
the encoded format for parent
"""
"""
items
=
[]
items
=
[]
for
parent_id
,
value
in
structure
[
'blocks'
]
.
iteritems
():
for
parent_id
,
value
in
structure
[
'blocks'
]
.
iteritems
():
...
@@ -1566,8 +1585,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1566,8 +1585,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
Return any newly discovered orphans (as a set)
Return any newly discovered orphans (as a set)
"""
"""
orphans
=
set
()
orphans
=
set
()
destination_block
=
destination_blocks
.
get
(
block_id
)
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
block_id
)
new_block
=
source_blocks
[
block_id
]
destination_block
=
destination_blocks
.
get
(
encoded_block_id
)
new_block
=
source_blocks
[
encoded_block_id
]
if
destination_block
:
if
destination_block
:
if
destination_block
[
'edit_info'
][
'update_version'
]
!=
new_block
[
'edit_info'
][
'update_version'
]:
if
destination_block
[
'edit_info'
][
'update_version'
]
!=
new_block
[
'edit_info'
][
'update_version'
]:
source_children
=
new_block
[
'fields'
][
'children'
]
source_children
=
new_block
[
'fields'
][
'children'
]
...
@@ -1591,7 +1611,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1591,7 +1611,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
for
child
in
destination_block
[
'fields'
]
.
get
(
'children'
,
[]):
for
child
in
destination_block
[
'fields'
]
.
get
(
'children'
,
[]):
if
child
not
in
blacklist
:
if
child
not
in
blacklist
:
orphans
.
update
(
self
.
_publish_subdag
(
user_id
,
child
,
source_blocks
,
destination_blocks
,
blacklist
))
orphans
.
update
(
self
.
_publish_subdag
(
user_id
,
child
,
source_blocks
,
destination_blocks
,
blacklist
))
destination_blocks
[
block_id
]
=
destination_block
destination_blocks
[
encoded_
block_id
]
=
destination_block
return
orphans
return
orphans
def
_filter_blacklist
(
self
,
fields
,
blacklist
):
def
_filter_blacklist
(
self
,
fields
,
blacklist
):
...
@@ -1607,9 +1627,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1607,9 +1627,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
Delete the orphan and any of its descendants which no longer have parents.
Delete the orphan and any of its descendants which no longer have parents.
"""
"""
if
not
self
.
_get_parents_from_structure
(
orphan
,
structure
):
if
not
self
.
_get_parents_from_structure
(
orphan
,
structure
):
for
child
in
structure
[
'blocks'
][
orphan
][
'fields'
]
.
get
(
'children'
,
[]):
encoded_block_id
=
LocMapperStore
.
encode_key_for_mongo
(
orphan
)
for
child
in
structure
[
'blocks'
][
encoded_block_id
][
'fields'
]
.
get
(
'children'
,
[]):
self
.
_delete_if_true_orphan
(
child
,
structure
)
self
.
_delete_if_true_orphan
(
child
,
structure
)
del
structure
[
'blocks'
][
orphan
]
del
structure
[
'blocks'
][
encoded_block_id
]
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
):
def
_new_block
(
self
,
user_id
,
category
,
block_fields
,
definition_id
,
new_id
):
return
{
return
{
...
@@ -1623,3 +1644,17 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1623,3 +1644,17 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'update_version'
:
new_id
'update_version'
:
new_id
}
}
}
}
def
_get_block_from_structure
(
self
,
structure
,
block_id
):
"""
Encodes the block id before retrieving it from the structure to ensure it can
be a json dict key.
"""
return
structure
[
'blocks'
]
.
get
(
LocMapperStore
.
encode_key_for_mongo
(
block_id
))
def
_update_block_in_structure
(
self
,
structure
,
block_id
,
content
):
"""
Encodes the block id before accessing it in the structure to ensure it can
be a json dict key.
"""
structure
[
'blocks'
][
LocMapperStore
.
encode_key_for_mongo
(
block_id
)]
=
content
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
View file @
41f88344
...
@@ -620,6 +620,34 @@ class TestItemCrud(SplitModuleTest):
...
@@ -620,6 +620,34 @@ class TestItemCrud(SplitModuleTest):
another_history
=
modulestore
()
.
get_definition_history_info
(
another_module
.
definition_locator
)
another_history
=
modulestore
()
.
get_definition_history_info
(
another_module
.
definition_locator
)
self
.
assertEqual
(
str
(
another_history
[
'previous_version'
]),
'0d00000040000000dddd0031'
)
self
.
assertEqual
(
str
(
another_history
[
'previous_version'
]),
'0d00000040000000dddd0031'
)
def
test_encoded_naming
(
self
):
"""
Check that using odd characters in block id don't break ability to add and retrieve block.
"""
parent_locator
=
BlockUsageLocator
(
package_id
=
"contender"
,
block_id
=
"head345679"
,
branch
=
'draft'
)
chapter_locator
=
BlockUsageLocator
(
package_id
=
"contender"
,
block_id
=
"foo.bar_-~:0"
,
branch
=
'draft'
)
modulestore
()
.
create_item
(
parent_locator
,
'chapter'
,
'anotheruser'
,
block_id
=
chapter_locator
.
block_id
,
fields
=
{
'display_name'
:
'chapter 99'
},
)
# check that course version changed and course's previous is the other one
new_module
=
modulestore
()
.
get_item
(
chapter_locator
)
self
.
assertEqual
(
new_module
.
location
.
block_id
,
"foo.bar_-~:0"
)
# hardcode to ensure BUL init didn't change
# now try making that a parent of something
new_payload
=
"<problem>empty</problem>"
problem_locator
=
BlockUsageLocator
(
package_id
=
"contender"
,
block_id
=
"prob.bar_-~:99a"
,
branch
=
'draft'
)
modulestore
()
.
create_item
(
chapter_locator
,
'problem'
,
'anotheruser'
,
block_id
=
problem_locator
.
block_id
,
fields
=
{
'display_name'
:
'chapter 99'
,
'data'
:
new_payload
},
)
# check that course version changed and course's previous is the other one
new_module
=
modulestore
()
.
get_item
(
problem_locator
)
self
.
assertEqual
(
new_module
.
location
.
block_id
,
problem_locator
.
block_id
)
chapter
=
modulestore
()
.
get_item
(
chapter_locator
)
self
.
assertIn
(
problem_locator
.
block_id
,
chapter
.
children
)
def
test_create_continue_version
(
self
):
def
test_create_continue_version
(
self
):
"""
"""
Test create_item using the continue_version flag
Test create_item using the continue_version flag
...
...
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