Commit 332d2b03 by Jonathan Piacenti Committed by E. Kolpakov

Addressed notes from reviewers about Library content filters.

parent 6ac25885
...@@ -58,6 +58,8 @@ registry = TagRegistry() ...@@ -58,6 +58,8 @@ registry = TagRegistry()
CorrectMap = correctmap.CorrectMap # pylint: disable=invalid-name CorrectMap = correctmap.CorrectMap # pylint: disable=invalid-name
CORRECTMAP_PY = None CORRECTMAP_PY = None
# Make '_' a no-op so we can scrape strings
_ = lambda text: text
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Exceptions # Exceptions
...@@ -439,6 +441,7 @@ class JavascriptResponse(LoncapaResponse): ...@@ -439,6 +441,7 @@ class JavascriptResponse(LoncapaResponse):
Javascript using Node.js. Javascript using Node.js.
""" """
human_name = _('Javascript Input')
tags = ['javascriptresponse'] tags = ['javascriptresponse']
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['javascriptinput'] allowed_inputfields = ['javascriptinput']
...@@ -684,6 +687,7 @@ class ChoiceResponse(LoncapaResponse): ...@@ -684,6 +687,7 @@ class ChoiceResponse(LoncapaResponse):
""" """
human_name = _('Checkboxes')
tags = ['choiceresponse'] tags = ['choiceresponse']
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['checkboxgroup', 'radiogroup'] allowed_inputfields = ['checkboxgroup', 'radiogroup']
...@@ -754,6 +758,7 @@ class MultipleChoiceResponse(LoncapaResponse): ...@@ -754,6 +758,7 @@ class MultipleChoiceResponse(LoncapaResponse):
""" """
# TODO: handle direction and randomize # TODO: handle direction and randomize
human_name = _('Multiple Choice')
tags = ['multiplechoiceresponse'] tags = ['multiplechoiceresponse']
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['choicegroup'] allowed_inputfields = ['choicegroup']
...@@ -1042,6 +1047,7 @@ class MultipleChoiceResponse(LoncapaResponse): ...@@ -1042,6 +1047,7 @@ class MultipleChoiceResponse(LoncapaResponse):
@registry.register @registry.register
class TrueFalseResponse(MultipleChoiceResponse): class TrueFalseResponse(MultipleChoiceResponse):
human_name = _('True/False Choice')
tags = ['truefalseresponse'] tags = ['truefalseresponse']
def mc_setup_response(self): def mc_setup_response(self):
...@@ -1073,6 +1079,7 @@ class OptionResponse(LoncapaResponse): ...@@ -1073,6 +1079,7 @@ class OptionResponse(LoncapaResponse):
TODO: handle direction and randomize TODO: handle direction and randomize
""" """
human_name = _('Dropdown')
tags = ['optionresponse'] tags = ['optionresponse']
hint_tag = 'optionhint' hint_tag = 'optionhint'
allowed_inputfields = ['optioninput'] allowed_inputfields = ['optioninput']
...@@ -1108,6 +1115,7 @@ class NumericalResponse(LoncapaResponse): ...@@ -1108,6 +1115,7 @@ class NumericalResponse(LoncapaResponse):
to a number (e.g. `4+5/2^2`), and accepts with a tolerance. to a number (e.g. `4+5/2^2`), and accepts with a tolerance.
""" """
human_name = _('Numerical Input')
tags = ['numericalresponse'] tags = ['numericalresponse']
hint_tag = 'numericalhint' hint_tag = 'numericalhint'
allowed_inputfields = ['textline', 'formulaequationinput'] allowed_inputfields = ['textline', 'formulaequationinput']
...@@ -1308,6 +1316,7 @@ class StringResponse(LoncapaResponse): ...@@ -1308,6 +1316,7 @@ class StringResponse(LoncapaResponse):
</hintgroup> </hintgroup>
</stringresponse> </stringresponse>
""" """
human_name = _('Text Input')
tags = ['stringresponse'] tags = ['stringresponse']
hint_tag = 'stringhint' hint_tag = 'stringhint'
allowed_inputfields = ['textline'] allowed_inputfields = ['textline']
...@@ -1426,6 +1435,7 @@ class CustomResponse(LoncapaResponse): ...@@ -1426,6 +1435,7 @@ class CustomResponse(LoncapaResponse):
or in a <script>...</script> or in a <script>...</script>
""" """
human_name = _('Custom Evaluated Script')
tags = ['customresponse'] tags = ['customresponse']
allowed_inputfields = ['textline', 'textbox', 'crystallography', allowed_inputfields = ['textline', 'textbox', 'crystallography',
...@@ -1800,6 +1810,7 @@ class SymbolicResponse(CustomResponse): ...@@ -1800,6 +1810,7 @@ class SymbolicResponse(CustomResponse):
Symbolic math response checking, using symmath library. Symbolic math response checking, using symmath library.
""" """
human_name = _('Symbolic Math Input')
tags = ['symbolicresponse'] tags = ['symbolicresponse']
max_inputfields = 1 max_inputfields = 1
...@@ -1868,6 +1879,7 @@ class CodeResponse(LoncapaResponse): ...@@ -1868,6 +1879,7 @@ class CodeResponse(LoncapaResponse):
""" """
human_name = _('Code Input')
tags = ['coderesponse'] tags = ['coderesponse']
allowed_inputfields = ['textbox', 'filesubmission', 'matlabinput'] allowed_inputfields = ['textbox', 'filesubmission', 'matlabinput']
max_inputfields = 1 max_inputfields = 1
...@@ -2145,6 +2157,7 @@ class ExternalResponse(LoncapaResponse): ...@@ -2145,6 +2157,7 @@ class ExternalResponse(LoncapaResponse):
""" """
human_name = _('External Grader')
tags = ['externalresponse'] tags = ['externalresponse']
allowed_inputfields = ['textline', 'textbox'] allowed_inputfields = ['textline', 'textbox']
awdmap = { awdmap = {
...@@ -2302,6 +2315,7 @@ class FormulaResponse(LoncapaResponse): ...@@ -2302,6 +2315,7 @@ class FormulaResponse(LoncapaResponse):
Checking of symbolic math response using numerical sampling. Checking of symbolic math response using numerical sampling.
""" """
human_name = _('Math Expression Input')
tags = ['formularesponse'] tags = ['formularesponse']
hint_tag = 'formulahint' hint_tag = 'formulahint'
allowed_inputfields = ['textline', 'formulaequationinput'] allowed_inputfields = ['textline', 'formulaequationinput']
...@@ -2514,6 +2528,7 @@ class SchematicResponse(LoncapaResponse): ...@@ -2514,6 +2528,7 @@ class SchematicResponse(LoncapaResponse):
""" """
Circuit schematic response type. Circuit schematic response type.
""" """
human_name = _('Circuit Schematic Builder')
tags = ['schematicresponse'] tags = ['schematicresponse']
allowed_inputfields = ['schematic'] allowed_inputfields = ['schematic']
...@@ -2592,6 +2607,7 @@ class ImageResponse(LoncapaResponse): ...@@ -2592,6 +2607,7 @@ class ImageResponse(LoncapaResponse):
True, if click is inside any region or rectangle. Otherwise False. True, if click is inside any region or rectangle. Otherwise False.
""" """
human_name = _('Image Mapped Input')
tags = ['imageresponse'] tags = ['imageresponse']
allowed_inputfields = ['imageinput'] allowed_inputfields = ['imageinput']
...@@ -2710,6 +2726,7 @@ class AnnotationResponse(LoncapaResponse): ...@@ -2710,6 +2726,7 @@ class AnnotationResponse(LoncapaResponse):
The response contains both a comment (student commentary) and an option (student tag). The response contains both a comment (student commentary) and an option (student tag).
Only the tag is currently graded. Answers may be incorrect, partially correct, or correct. Only the tag is currently graded. Answers may be incorrect, partially correct, or correct.
""" """
human_name = _('Annotation Input')
tags = ['annotationresponse'] tags = ['annotationresponse']
allowed_inputfields = ['annotationinput'] allowed_inputfields = ['annotationinput']
max_inputfields = 1 max_inputfields = 1
...@@ -2834,6 +2851,7 @@ class ChoiceTextResponse(LoncapaResponse): ...@@ -2834,6 +2851,7 @@ class ChoiceTextResponse(LoncapaResponse):
ChoiceResponse. ChoiceResponse.
""" """
human_name = _('Checkboxes With Text Input')
tags = ['choicetextresponse'] tags = ['choicetextresponse']
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['choicetextgroup', allowed_inputfields = ['choicetextgroup',
......
...@@ -5,6 +5,7 @@ LibraryContent: The XBlock used to include blocks from a library in a course. ...@@ -5,6 +5,7 @@ LibraryContent: The XBlock used to include blocks from a library in a course.
from bson.objectid import ObjectId, InvalidId from bson.objectid import ObjectId, InvalidId
from collections import namedtuple from collections import namedtuple
from copy import copy from copy import copy
from capa.responsetypes import registry
from .mako_module import MakoModuleDescriptor from .mako_module import MakoModuleDescriptor
from opaque_keys import InvalidKeyError from opaque_keys import InvalidKeyError
...@@ -33,34 +34,18 @@ def enum(**enums): ...@@ -33,34 +34,18 @@ def enum(**enums):
return type('Enum', (), enums) return type('Enum', (), enums)
def _get_human_name(problem_class):
"""
Get the human-friendly name for a problem type.
"""
return getattr(problem_class, 'human_name', problem_class.__name__)
def _get_capa_types(): def _get_capa_types():
""" """
Gets capa types tags and labels Gets capa types tags and labels
""" """
capa_types = { capa_types = {tag: _get_human_name(registry.get_class_for_tag(tag)) for tag in registry.registered_tags()}
# basic tab
'choiceresponse': _('Checkboxes'),
'optionresponse': _('Dropdown'),
'multiplechoiceresponse': _('Multiple Choice'),
'truefalseresponse': _('True/False Choice'),
'numericalresponse': _('Numerical Input'),
'stringresponse': _('Text Input'),
# advanced tab
'schematicresponse': _('Circuit Schematic Builder'),
'customresponse': _('Custom Evaluated Script'),
'imageresponse': _('Image Mapped Input'),
'formularesponse': _('Math Expression Input'),
'jsmeresponse': _('Molecular Structure'),
# not in "Add Component" menu
'javascriptresponse': _('Javascript Input'),
'symbolicresponse': _('Symbolic Math Input'),
'coderesponse': _('Code Input'),
'externalresponse': _('External Grader'),
'annotationresponse': _('Annotation Input'),
'choicetextresponse': _('Checkboxes With Text Input'),
}
return [{'value': ANY_CAPA_TYPE_VALUE, 'display_name': _('Any Type')}] + sorted([ return [{'value': ANY_CAPA_TYPE_VALUE, 'display_name': _('Any Type')}] + sorted([
{'value': capa_type, 'display_name': caption} {'value': capa_type, 'display_name': caption}
...@@ -429,9 +414,9 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe ...@@ -429,9 +414,9 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
validation, validation,
StudioValidationMessage( StudioValidationMessage(
StudioValidationMessage.WARNING, StudioValidationMessage.WARNING,
_(u'There are no content matching configured filters in the selected libraries.'), _(u'There are no matching problem types in the specified libraries.'),
action_class='edit-button', action_class='edit-button',
action_label=_(u"Edit Problem Type Filter") action_label=_(u"Select another problem type")
) )
) )
...@@ -440,10 +425,11 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe ...@@ -440,10 +425,11 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
validation, validation,
StudioValidationMessage( StudioValidationMessage(
StudioValidationMessage.WARNING, StudioValidationMessage.WARNING,
_(u'Configured to fetch {count} blocks, library and filter settings yield only {actual} blocks.') _(u'The specified libraries are configured to fetch {count} problems, '
u'but there are only {actual} matching problems.')
.format(actual=matching_children_count, count=self.max_count), .format(actual=matching_children_count, count=self.max_count),
action_class='edit-button', action_class='edit-button',
action_label=_(u"Edit block configuration") action_label=_(u"Edit configuration")
) )
) )
......
...@@ -28,7 +28,10 @@ class LibraryContentTestBase(UniqueCourseTest): ...@@ -28,7 +28,10 @@ class LibraryContentTestBase(UniqueCourseTest):
STAFF_EMAIL = "staff101@example.com" STAFF_EMAIL = "staff101@example.com"
def populate_library_fixture(self, library_fixture): def populate_library_fixture(self, library_fixture):
pass """
To be overwritten by subclassed tests. Used to install a library to
run tests on.
"""
def setUp(self): def setUp(self):
""" """
...@@ -207,7 +210,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase): ...@@ -207,7 +210,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase):
def _get_problem_select_text(self, name, items, correct): def _get_problem_select_text(self, name, items, correct):
""" Generates Select Option CAPA problem XML """ """ Generates Select Option CAPA problem XML """
items_text = ",".join(map(lambda item: "'{0}'".format(item), items)) items_text = ",".join(["'{0}'".format(item) for item in items])
return """<problem> return """<problem>
<p>{name}</p> <p>{name}</p>
...@@ -281,7 +284,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase): ...@@ -281,7 +284,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase):
self.assertEqual(len(children_headers), 1) self.assertEqual(len(children_headers), 1)
self.assertLessEqual( self.assertLessEqual(
children_headers, children_headers,
set(map(lambda header: header.upper(), ["Problem Choice Group 1", "Problem Choice Group 2"])) set([header.upper() for header in ["Problem Choice Group 1", "Problem Choice Group 2"]])
) )
# Choice group test # Choice group test
...@@ -289,7 +292,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase): ...@@ -289,7 +292,7 @@ class StudioLibraryContainerCapaFilterTest(LibraryContentTestBase):
self.assertEqual(len(children_headers), 2) self.assertEqual(len(children_headers), 2)
self.assertLessEqual( self.assertLessEqual(
children_headers, children_headers,
set(map(lambda header: header.upper(), ["Problem Select 1", "Problem Select 2"])) set([header.upper() for header in ["Problem Select 1", "Problem Select 2"]])
) )
# Missing problem type test # Missing problem type test
......
...@@ -189,8 +189,7 @@ class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest): ...@@ -189,8 +189,7 @@ class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest):
When I set Problem Type selector so that there are matching content When I set Problem Type selector so that there are matching content
Then I can see that warning messages are not shown Then I can see that warning messages are not shown
""" """
expected_text = 'There are no content matching configured filters in the selected libraries. ' \ expected_text = 'There are no matching problem types in the specified libraries. Select another problem type'
'Edit Problem Type Filter'
library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0]) library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0])
...@@ -223,7 +222,8 @@ class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest): ...@@ -223,7 +222,8 @@ class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest):
And I set Problem Type selector so "Any" And I set Problem Type selector so "Any"
Then I can see that "No matching content" warning is shown Then I can see that "No matching content" warning is shown
""" """
expected_tpl = "Configured to fetch {count} blocks, library and filter settings yield only {actual} blocks." expected_tpl = "The specified libraries are configured to fetch {count} problems, " \
"but there are only {actual} matching problems."
library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0]) library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[0])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment