Problem type filtering on update_children event
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from lxml import etree
|
||||
|
||||
from pkg_resources import resource_string
|
||||
|
||||
from .capa_base import CapaMixin, CapaFields, ComplexEncoder
|
||||
from capa import inputtypes
|
||||
from .progress import Progress
|
||||
from xmodule.x_module import XModule, module_attr
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
@@ -172,6 +174,13 @@ class CapaDescriptor(CapaFields, RawDescriptor):
|
||||
])
|
||||
return non_editable_fields
|
||||
|
||||
@property
|
||||
def problem_types(self):
|
||||
""" Low-level problem type introspection for content libraries filtering by problem type """
|
||||
tree = etree.XML(self.data)
|
||||
registered_tas = inputtypes.registry.registered_tags()
|
||||
return set([node.tag for node in tree.iter() if node.tag in registered_tas])
|
||||
|
||||
# Proxy to CapaModule for access to any of its attributes
|
||||
answer_available = module_attr('answer_available')
|
||||
check_button_name = module_attr('check_button_name')
|
||||
|
||||
@@ -222,23 +222,6 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule):
|
||||
as children of this block, but only a subset of those children are shown to
|
||||
any particular student.
|
||||
"""
|
||||
def _filter_children(self, child_locator):
|
||||
"""
|
||||
Filters children by CAPA problem type, if configured
|
||||
"""
|
||||
if self.capa_type == ANY_CAPA_TYPE_VALUE:
|
||||
return True
|
||||
|
||||
if child_locator.block_type != CAPA_BLOCK_TYPE:
|
||||
return False
|
||||
|
||||
block = self.runtime.get_block(child_locator)
|
||||
|
||||
if not hasattr(block, 'lcp'):
|
||||
return True
|
||||
|
||||
return any(self.capa_type in capa_input.tags for capa_input in block.lcp.inputs.values())
|
||||
|
||||
def selected_children(self):
|
||||
"""
|
||||
Returns a set() of block_ids indicating which of the possible children
|
||||
@@ -255,7 +238,7 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule):
|
||||
return self._selected_set # pylint: disable=access-member-before-definition
|
||||
# Determine which of our children we will show:
|
||||
selected = set(tuple(k) for k in self.selected) # set of (block_type, block_id) tuples
|
||||
valid_block_keys = set([(c.block_type, c.block_id) for c in self.children if self._filter_children(c)]) # pylint: disable=no-member
|
||||
valid_block_keys = set([(c.block_type, c.block_id) for c in self.children]) # pylint: disable=no-member
|
||||
# Remove any selected blocks that are no longer valid:
|
||||
selected -= (selected - valid_block_keys)
|
||||
# If max_count has been decreased, we may have to drop some previously selected blocks:
|
||||
|
||||
@@ -5,8 +5,9 @@ import hashlib
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from opaque_keys.edx.locator import LibraryLocator
|
||||
from xblock.fields import Scope
|
||||
from xmodule.library_content_module import LibraryVersionReference
|
||||
from xmodule.library_content_module import LibraryVersionReference, ANY_CAPA_TYPE_VALUE
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.capa_module import CapaDescriptor
|
||||
|
||||
|
||||
class LibraryToolsService(object):
|
||||
@@ -45,6 +46,18 @@ class LibraryToolsService(object):
|
||||
return library.location.library_key.version_guid
|
||||
return None
|
||||
|
||||
def _filter_child(self, dest_block, child_descriptor):
|
||||
"""
|
||||
Filters children by CAPA problem type, if configured
|
||||
"""
|
||||
if dest_block.capa_type == ANY_CAPA_TYPE_VALUE:
|
||||
return True
|
||||
|
||||
if not isinstance(child_descriptor, CapaDescriptor):
|
||||
return False
|
||||
|
||||
return dest_block.capa_type in child_descriptor.problem_types
|
||||
|
||||
def update_children(self, dest_block, user_id, user_perms=None, update_db=True):
|
||||
"""
|
||||
This method is to be used when any of the libraries that a LibraryContentModule
|
||||
@@ -91,13 +104,16 @@ class LibraryToolsService(object):
|
||||
new_libraries = []
|
||||
for library_key, library in libraries:
|
||||
|
||||
def copy_children_recursively(from_block):
|
||||
def copy_children_recursively(from_block, filter_problem_type=True):
|
||||
"""
|
||||
Internal method to copy blocks from the library recursively
|
||||
"""
|
||||
new_children = []
|
||||
for child_key in from_block.children:
|
||||
child = self.store.get_item(child_key, depth=9)
|
||||
|
||||
if filter_problem_type and not self._filter_child(dest_block, child):
|
||||
continue
|
||||
# We compute a block_id for each matching child block found in the library.
|
||||
# block_ids are unique within any branch, but are not unique per-course or globally.
|
||||
# We need our block_ids to be consistent when content in the library is updated, so
|
||||
@@ -125,7 +141,7 @@ class LibraryToolsService(object):
|
||||
)
|
||||
new_children.append(new_child_info.location)
|
||||
return new_children
|
||||
root_children.extend(copy_children_recursively(from_block=library))
|
||||
root_children.extend(copy_children_recursively(from_block=library, filter_problem_type=True))
|
||||
new_libraries.append(LibraryVersionReference(library_key, library.location.library_key.version_guid))
|
||||
dest_block.source_libraries = new_libraries
|
||||
dest_block.children = root_children
|
||||
|
||||
Reference in New Issue
Block a user