Files
edx-platform/lms/djangoapps/courseware/management/commands/dump_course_structure.py
0x29a 9d8375ff99 refactor: rename module -> block within lms/djangoapps/courseware
Also, removed unused `_has_access_xmodule` methid from `lms/djangoapps/courseware/access.py`.
2023-01-30 18:15:22 +01:00

126 lines
4.1 KiB
Python

"""
Dump the structure of a course as a JSON object.
The resulting JSON object has one entry for each block in the course:
{
"$block_url": {
"category": "$block_category",
"children": [$block_children_urls... ],
"metadata": {$block_metadata}
},
"$block_url": ....
...
}
"""
import json
from textwrap import dedent
from django.core.management.base import BaseCommand, CommandError
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from xblock.fields import Scope
from xmodule.discussion_block import DiscussionXBlock
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.inheritance import compute_inherited_metadata, own_metadata
FILTER_LIST = ['xml_attributes']
INHERITED_FILTER_LIST = ['children', 'xml_attributes']
class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docstring
help = dedent(__doc__).strip()
def add_arguments(self, parser):
parser.add_argument('course_id',
help='specifies the course to dump')
parser.add_argument('--modulestore',
default='default',
help='name of the modulestore')
parser.add_argument('--inherited',
action='store_true',
help='include inherited metadata')
parser.add_argument('--inherited_defaults',
action='store_true',
help='include default values of inherited metadata')
def handle(self, *args, **options):
# Get the modulestore
store = modulestore()
# Get the course data
try:
course_key = CourseKey.from_string(options['course_id'])
except InvalidKeyError:
raise CommandError("Invalid course_id") # lint-amnesty, pylint: disable=raise-missing-from
course = store.get_course(course_key)
if course is None:
raise CommandError("Invalid course_id")
# Precompute inherited metadata at the course level, if needed:
if options['inherited']:
compute_inherited_metadata(course)
# Convert course data to dictionary and dump it as JSON to stdout
info = dump_block(course, inherited=options['inherited'], defaults=options['inherited_defaults'])
return json.dumps(info, indent=2, sort_keys=True, default=str)
def dump_block(block, destination=None, inherited=False, defaults=False):
"""
Add the block and all its children to the destination dictionary in
as a flat structure.
"""
destination = destination if destination else {}
items = own_metadata(block)
# HACK: add discussion ids to list of items to export (AN-6696)
if isinstance(block, DiscussionXBlock) and 'discussion_id' not in items:
items['discussion_id'] = block.discussion_id
filtered_metadata = {k: v for k, v in items.items() if k not in FILTER_LIST}
destination[str(block.location)] = {
'category': block.location.block_type,
'children': [str(child) for child in getattr(block, 'children', [])],
'metadata': filtered_metadata,
}
if inherited:
# When calculating inherited metadata, don't include existing
# locally-defined metadata
inherited_metadata_filter_list = list(filtered_metadata.keys())
inherited_metadata_filter_list.extend(INHERITED_FILTER_LIST)
def is_inherited(field):
if field.name in inherited_metadata_filter_list:
return False
elif field.scope != Scope.settings:
return False
elif defaults:
return True
else:
return field.values != field.default
inherited_metadata = {field.name: field.read_json(block) for field in block.fields.values() if is_inherited(field)} # lint-amnesty, pylint: disable=line-too-long
destination[str(block.location)]['inherited_metadata'] = inherited_metadata
for child in block.get_children():
dump_block(child, destination, inherited, defaults)
return destination