Add a fix_not_found command to get rid
of dangling children references to blocks. TNL-1141
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
Script for fixing the item not found errors in a course
|
||||
"""
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
# To run from command line: ./manage.py cms fix_not_found course-v1:org+course+run
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""Fix a course's item not found errors"""
|
||||
help = "Fix a course's ItemNotFound errors"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"Execute the command"
|
||||
if len(args) != 1:
|
||||
raise CommandError("requires 1 argument: <course_id>")
|
||||
|
||||
course_key = CourseKey.from_string(args[0])
|
||||
# for now only support on split mongo
|
||||
owning_store = modulestore()._get_modulestore_for_courseid(course_key)
|
||||
if hasattr(owning_store, 'fix_not_found'):
|
||||
owning_store.fix_not_found(course_key, ModuleStoreEnum.UserID.mgmt_command)
|
||||
else:
|
||||
raise CommandError("The owning modulestore does not support this command.")
|
||||
@@ -119,7 +119,7 @@ class SplitMigrator(object):
|
||||
|
||||
# clean up orphans in published version: in old mongo, parents pointed to the union of their published and draft
|
||||
# children which meant some pointers were to non-existent locations in 'direct'
|
||||
self.split_modulestore.internal_clean_children(course_version_locator)
|
||||
self.split_modulestore.fix_not_found(course_version_locator, user_id)
|
||||
|
||||
def _add_draft_modules_to_course(self, published_course_usage_key, source_course_key, user_id, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -2418,22 +2418,26 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
||||
# update the index entry if appropriate
|
||||
self._update_head(dest_course_key, index_entry, dest_course_key.branch, new_structure['_id'])
|
||||
|
||||
def internal_clean_children(self, course_locator):
|
||||
def fix_not_found(self, course_locator, user_id):
|
||||
"""
|
||||
Only intended for rather low level methods to use. Goes through the children attrs of
|
||||
each block removing any whose block_id is not a member of the course. Does not generate
|
||||
a new version of the course but overwrites the existing one.
|
||||
each block removing any whose block_id is not a member of the course.
|
||||
|
||||
:param course_locator: the course to clean
|
||||
"""
|
||||
original_structure = self._lookup_course(course_locator).structure
|
||||
for block in original_structure['blocks'].itervalues():
|
||||
index_entry = self._get_index_if_valid(course_locator)
|
||||
new_structure = self.version_structure(course_locator, original_structure, user_id)
|
||||
for block in new_structure['blocks'].itervalues():
|
||||
if 'fields' in block and 'children' in block['fields']:
|
||||
block['fields']["children"] = [
|
||||
block_id for block_id in block['fields']["children"]
|
||||
if block_id in original_structure['blocks']
|
||||
if block_id in new_structure['blocks']
|
||||
]
|
||||
self.update_structure(course_locator, original_structure)
|
||||
self.update_structure(course_locator, new_structure)
|
||||
if index_entry is not None:
|
||||
# update the index entry if appropriate
|
||||
self._update_head(course_locator, index_entry, course_locator.branch, new_structure['_id'])
|
||||
|
||||
def convert_references_to_keys(self, course_key, xblock_class, jsonfields, blocks):
|
||||
"""
|
||||
|
||||
@@ -251,6 +251,16 @@ class DraftVersioningModuleStore(SplitMongoModuleStore, ModuleStoreDraftAndPubli
|
||||
course_key = self._map_revision_to_branch(course_key)
|
||||
return super(DraftVersioningModuleStore, self).get_orphans(course_key, **kwargs)
|
||||
|
||||
def fix_not_found(self, course_key, user_id):
|
||||
"""
|
||||
Fix any children which point to non-existent blocks in the course's published and draft branches
|
||||
"""
|
||||
for branch in [ModuleStoreEnum.RevisionOption.published_only, ModuleStoreEnum.RevisionOption.draft_only]:
|
||||
super(DraftVersioningModuleStore, self).fix_not_found(
|
||||
self._map_revision_to_branch(course_key, branch),
|
||||
user_id
|
||||
)
|
||||
|
||||
def has_changes(self, xblock):
|
||||
"""
|
||||
Checks if the given block has unpublished changes
|
||||
|
||||
Reference in New Issue
Block a user