Convert AboutModule, CourseInfoModule, HtmlModule and StaticTabModule to XBlocks.

This commit is contained in:
Usman Khalid
2019-07-06 03:18:38 +05:00
parent 8526a989c3
commit 8dfc8e5fda
21 changed files with 139 additions and 153 deletions

View File

@@ -22,7 +22,7 @@ from django.utils.translation import ugettext as _
from cms.djangoapps.contentstore.push_notification import enqueue_push_course_update
from openedx.core.lib.xblock_utils import get_course_update_items
from xmodule.html_module import CourseInfoModule
from xmodule.html_module import CourseInfoBlock
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -76,7 +76,7 @@ def update_course_updates(location, update, passed_id=None, user=None):
"id": len(course_update_items) + 1,
"date": update["date"],
"content": update["content"],
"status": CourseInfoModule.STATUS_VISIBLE
"status": CourseInfoBlock.STATUS_VISIBLE
}
course_update_items.append(course_update_dict)
enqueue_push_course_update(update, location.course_key)
@@ -106,14 +106,14 @@ def _get_visible_update(course_update_items):
"""
if isinstance(course_update_items, dict):
# single course update item
if course_update_items.get("status") != CourseInfoModule.STATUS_DELETED:
if course_update_items.get("status") != CourseInfoBlock.STATUS_DELETED:
return _make_update_dict(course_update_items)
else:
# requested course update item has been deleted (soft delete)
return {"error": _("Course update not found."), "status": 404}
return ([_make_update_dict(update) for update in course_update_items
if update.get("status") != CourseInfoModule.STATUS_DELETED])
if update.get("status") != CourseInfoBlock.STATUS_DELETED])
# pylint: disable=unused-argument
@@ -138,7 +138,7 @@ def delete_course_update(location, update, passed_id, user):
if 0 < passed_index <= len(course_update_items):
course_update_item = course_update_items[passed_index - 1]
# soft delete course update item
course_update_item["status"] = CourseInfoModule.STATUS_DELETED
course_update_item["status"] = CourseInfoBlock.STATUS_DELETED
course_update_items[passed_index - 1] = course_update_item
# update db record

View File

@@ -116,6 +116,6 @@ class TestDeleteOrphan(TestOrphanBase):
# there should be one in published
self.assertOrphanCount(course.id, 0)
self.assertOrphanCount(published_branch, 1)
self.assertIn(orphan, self.store.get_items(published_branch))
self.assertIn(orphan.location, [x.location for x in self.store.get_items(published_branch)])
return course, orphan

View File

@@ -5,7 +5,7 @@ from __future__ import absolute_import
from xmodule import templates
from xmodule.capa_module import ProblemBlock
from xmodule.course_module import CourseDescriptor
from xmodule.html_module import HtmlDescriptor
from xmodule.html_module import HtmlBlock
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.exceptions import DuplicateCourseError
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, ModuleStoreTestCase
@@ -44,10 +44,10 @@ class TemplateTests(ModuleStoreTestCase):
def test_get_some_templates(self):
self.assertEqual(len(SequenceDescriptor.templates()), 0)
self.assertGreater(len(HtmlDescriptor.templates()), 0)
self.assertGreater(len(HtmlBlock.templates()), 0)
self.assertIsNone(SequenceDescriptor.get_template('doesntexist.yaml'))
self.assertIsNone(HtmlDescriptor.get_template('doesntexist.yaml'))
self.assertIsNotNone(HtmlDescriptor.get_template('announcement.yaml'))
self.assertIsNone(HtmlBlock.get_template('doesntexist.yaml'))
self.assertIsNotNone(HtmlBlock.get_template('announcement.yaml'))
def test_factories(self):
test_course = CourseFactory.create(

View File

@@ -680,7 +680,7 @@ class TestCourseReIndex(CourseTestCase):
self.assertIn(self.SUCCESSFUL_RESPONSE, response.content)
self.assertEqual(response.status_code, 200)
@mock.patch('xmodule.html_module.HtmlDescriptor.index_dictionary')
@mock.patch('xmodule.html_module.HtmlBlock.index_dictionary')
def test_reindex_course_search_index_error(self, mock_index_dictionary):
"""
Test json response with mocked error data for html
@@ -743,7 +743,7 @@ class TestCourseReIndex(CourseTestCase):
with self.assertRaises(SearchIndexingError):
reindex_course_and_check_access(self.course.id, self.user)
@mock.patch('xmodule.html_module.HtmlDescriptor.index_dictionary')
@mock.patch('xmodule.html_module.HtmlBlock.index_dictionary')
def test_reindex_html_error_json_responses(self, mock_index_dictionary):
"""
Test json response with mocked error data for html
@@ -853,7 +853,7 @@ class TestCourseReIndex(CourseTestCase):
with self.assertRaises(SearchIndexingError):
CoursewareSearchIndexer.do_course_reindex(modulestore(), self.course.id)
@mock.patch('xmodule.html_module.HtmlDescriptor.index_dictionary')
@mock.patch('xmodule.html_module.HtmlBlock.index_dictionary')
def test_indexing_html_error_responses(self, mock_index_dictionary):
"""
Test do_course_reindex response with mocked error data for html

View File

@@ -7,7 +7,6 @@ XMODULES = [
"course = xmodule.course_module:CourseDescriptor",
"customtag = xmodule.template_module:CustomTagDescriptor",
"discuss = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"html = xmodule.html_module:HtmlDescriptor",
"image = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"library_content = xmodule.library_content_module:LibraryContentDescriptor",
"error = xmodule.error_module:ErrorDescriptor",
@@ -20,10 +19,7 @@ XMODULES = [
"slides = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"videosequence = xmodule.seq_module:SequenceDescriptor",
"course_info = xmodule.html_module:CourseInfoDescriptor",
"static_tab = xmodule.html_module:StaticTabDescriptor",
"custom_tag_template = xmodule.raw_module:RawDescriptor",
"about = xmodule.html_module:AboutDescriptor",
"annotatable = xmodule.annotatable_module:AnnotatableDescriptor",
"word_cloud = xmodule.word_cloud_module:WordCloudDescriptor",
"hidden = xmodule.hidden_module:HiddenDescriptor",
@@ -31,8 +27,12 @@ XMODULES = [
"lti = xmodule.lti_module:LTIDescriptor",
]
XBLOCKS = [
"about = xmodule.html_module:AboutBlock",
"course_info = xmodule.html_module:CourseInfoBlock",
"html = xmodule.html_module:HtmlBlock",
"library = xmodule.library_root_xblock:LibraryRoot",
"problem = xmodule.capa_module:ProblemBlock",
"static_tab = xmodule.html_module:StaticTabBlock",
"vertical = xmodule.vertical_block:VerticalBlock",
"video = xmodule.video_module:VideoBlock",
"videoalpha = xmodule.video_module:VideoBlock",

View File

@@ -19,13 +19,21 @@ from web_fragments.fragment import Fragment
from xblock.core import XBlock
from xblock.fields import Boolean, List, Scope, String
from xmodule.contentstore.content import StaticContent
from xmodule.editing_module import EditingDescriptor
from xmodule.editing_module import EditingMixin
from xmodule.edxnotes_utils import edxnotes
from xmodule.html_checker import check_html
from xmodule.stringify import stringify_children
from xmodule.util.misc import escape_html_characters
from xmodule.x_module import DEPRECATION_VSCOMPAT_EVENT, XModule
from xmodule.xml_module import XmlDescriptor, name_to_pathname
from xmodule.util.xmodule_django import add_webpack_to_fragment
from xmodule.x_module import (
HTMLSnippet,
ResourceTemplates,
shim_xmodule_js,
XModuleMixin,
XModuleDescriptorToXBlockMixin,
XModuleToXBlockMixin,
)
from xmodule.xml_module import XmlMixin, name_to_pathname
log = logging.getLogger("edx.courseware")
@@ -34,11 +42,14 @@ log = logging.getLogger("edx.courseware")
_ = lambda text: text
class HtmlBlock(object):
@edxnotes
@XBlock.needs("i18n")
class HtmlBlock(
XmlMixin, EditingMixin,
XModuleDescriptorToXBlockMixin, XModuleToXBlockMixin, HTMLSnippet, ResourceTemplates, XModuleMixin,
):
"""
This will eventually subclass XBlock and merge HtmlModule and HtmlDescriptor
into one. For now, it's a place to put the pieces that are already sharable
between the two (field information and XBlock handlers).
The HTML XBlock.
"""
display_name = String(
display_name=_("Display Name"),
@@ -79,7 +90,10 @@ class HtmlBlock(object):
"""
Return a fragment that contains the html for the student view
"""
return Fragment(self.get_html())
fragment = Fragment(self.get_html())
add_webpack_to_fragment(fragment, 'HtmlBlockPreview')
shim_xmodule_js(fragment, 'HTMLModule')
return fragment
@XBlock.supports("multi_device")
def public_view(self, context):
@@ -101,54 +115,56 @@ class HtmlBlock(object):
}
def get_html(self):
""" Returns html required for rendering XModule. """
# When we switch this to an XBlock, we can merge this with student_view,
# but for now the XModule mixin requires that this method be defined.
""" Returns html required for rendering the block. """
# pylint: disable=no-member
if self.data is not None and getattr(self.system, 'anonymous_student_id', None) is not None:
return self.data.replace("%%USER_ID%%", self.system.anonymous_student_id)
return self.data
def studio_view(self, _context):
"""
Return the studio view.
"""
fragment = Fragment(
self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'HtmlBlockStudio')
shim_xmodule_js(fragment, 'HTMLEditingDescriptor')
return fragment
class HtmlModuleMixin(HtmlBlock, XModule):
"""
Attributes and methods used by HtmlModules internally.
"""
js = {
preview_view_js = {
'js': [
resource_string(__name__, 'js/src/html/display.js'),
resource_string(__name__, 'js/src/javascript_loader.js'),
resource_string(__name__, 'js/src/collapsible.js'),
resource_string(__name__, 'js/src/html/imageModal.js'),
resource_string(__name__, 'js/common_static/js/vendor/draggabilly.js'),
]
],
'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'),
}
js_module_name = "HTMLModule"
css = {'scss': [resource_string(__name__, 'css/html/display.scss')]}
preview_view_css = {'scss': [resource_string(__name__, 'css/html/display.scss')]}
uses_xmodule_styles_setup = True
requires_per_student_anonymous_id = True
@edxnotes
class HtmlModule(HtmlModuleMixin):
"""
Module for putting raw html in a course
"""
class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: disable=abstract-method
"""
Module for putting raw html in a course
"""
mako_template = "widgets/html-edit.html"
module_class = HtmlModule
resources_dir = None
filename_extension = "xml"
template_dir_name = "html"
show_in_read_only_mode = True
js = {'js': [resource_string(__name__, 'js/src/html/edit.js')]}
js_module_name = "HTMLEditingDescriptor"
css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]}
studio_view_js = {
'js': [
resource_string(__name__, 'js/src/html/edit.js')
],
'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'),
}
studio_view_css = {
'scss': [
resource_string(__name__, 'css/editor/edit.scss'),
resource_string(__name__, 'css/html/edit.scss')
]
}
# VS[compat] TODO (cpennington): Delete this method once all fall 2012 course
# are being edited in the cms
@@ -188,7 +204,7 @@ class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: di
an override to add in specific rendering context, in this case we need to
add in a base path to our c4x content addressing scheme
"""
_context = EditingDescriptor.get_context(self)
_context = EditingMixin.get_context(self)
# Add some specific HTML rendering context when editing HTML modules where we pass
# the root /c4x/ url for assets. This allows client-side substitutions to occur.
_context.update({
@@ -308,12 +324,12 @@ class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: di
"""
`use_latex_compiler` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(HtmlDescriptor, self).non_editable_metadata_fields
non_editable_fields.append(HtmlDescriptor.use_latex_compiler)
non_editable_fields = super(HtmlBlock, self).non_editable_metadata_fields
non_editable_fields.append(HtmlBlock.use_latex_compiler)
return non_editable_fields
def index_dictionary(self):
xblock_body = super(HtmlDescriptor, self).index_dictionary()
xblock_body = super(HtmlBlock, self).index_dictionary()
# Removing script and style
html_content = re.sub(
re.compile(
@@ -353,21 +369,12 @@ class AboutFields(object):
@XBlock.tag("detached")
class AboutModule(AboutFields, HtmlModuleMixin):
class AboutBlock(AboutFields, HtmlBlock):
"""
Overriding defaults but otherwise treated as HtmlModule.
"""
pass
@XBlock.tag("detached")
class AboutDescriptor(AboutFields, HtmlDescriptor):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
These pieces of course content are treated as HtmlBlocks but we need to overload where the templates are located
in order to be able to create new ones
"""
template_dir_name = "about"
module_class = AboutModule
class StaticTabFields(object):
@@ -397,21 +404,12 @@ class StaticTabFields(object):
@XBlock.tag("detached")
class StaticTabModule(StaticTabFields, HtmlModuleMixin):
class StaticTabBlock(StaticTabFields, HtmlBlock):
"""
Supports the field overrides
"""
pass
@XBlock.tag("detached")
class StaticTabDescriptor(StaticTabFields, HtmlDescriptor):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
These pieces of course content are treated as HtmlBlocks but we need to overload where the templates are located
in order to be able to create new ones
"""
template_dir_name = None
module_class = StaticTabModule
class CourseInfoFields(object):
@@ -431,21 +429,17 @@ class CourseInfoFields(object):
@XBlock.tag("detached")
class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
class CourseInfoBlock(CourseInfoFields, HtmlBlock):
"""
Just to support xblock field overrides
These pieces of course content are treated as HtmlBlock but we need to overload where the templates are located
in order to be able to create new ones
"""
# statuses
STATUS_VISIBLE = 'visible'
STATUS_DELETED = 'deleted'
TEMPLATE_DIR = 'courseware'
@XBlock.supports("multi_device")
def student_view(self, _context):
"""
Return a fragment that contains the html for the student view
"""
return Fragment(self.get_html())
template_dir_name = None
def get_html(self):
""" Returns html required for rendering XModule. """
@@ -488,13 +482,3 @@ class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
return datetime.strptime(date, '%B %d, %Y')
except ValueError: # occurs for ill-formatted date values
return datetime.today()
@XBlock.tag("detached")
class CourseInfoDescriptor(CourseInfoFields, HtmlDescriptor):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
in order to be able to create new ones
"""
template_dir_name = None
module_class = CourseInfoModule

View File

@@ -133,7 +133,7 @@ class TestXMLModuleStore(TestCase):
self.assertIsNotNone(parent, "get_parent failed to return a value")
parent_loc = course_key.make_usage_key('vertical', 'vertical_test')
self.assertEqual(parent.location, parent_loc)
self.assertIn(shared_item, parent.get_children())
self.assertIn(shared_item.location, [x.location for x in parent.get_children()])
# ensure it's still a child of the other parent even tho it doesn't claim the other parent as its parent
other_parent_loc = course_key.make_usage_key('vertical', 'zeta')
other_parent = store.get_item(other_parent_loc)

View File

@@ -22,6 +22,7 @@ from docopt import docopt
from path import Path as path
from xmodule.capa_module import ProblemBlock
from xmodule.html_module import AboutBlock, CourseInfoBlock, HtmlBlock, StaticTabBlock
from xmodule.x_module import XModuleDescriptor, HTMLSnippet
LOG = logging.getLogger(__name__)
@@ -63,7 +64,11 @@ class VideoBlock(HTMLSnippet):
# List of XBlocks which use this static content setup.
# Should only be used for XModules being converted to XBlocks.
XBLOCK_CLASSES = [
AboutBlock,
CourseInfoBlock,
HtmlBlock,
ProblemBlock,
StaticTabBlock,
VideoBlock,
]

View File

@@ -9,7 +9,7 @@ from opaque_keys.edx.locator import CourseLocator
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from xmodule.html_module import CourseInfoModule, HtmlDescriptor, HtmlModule
from xmodule.html_module import CourseInfoBlock, HtmlBlock
from ..x_module import PUBLIC_VIEW, STUDENT_VIEW
from . import get_test_descriptor_system, get_test_system
@@ -23,14 +23,14 @@ def instantiate_descriptor(**field_data):
course_key = CourseLocator('org', 'course', 'run')
usage_key = course_key.make_usage_key('html', 'SampleHtml')
return system.construct_xblock_from_class(
HtmlDescriptor,
HtmlBlock,
scope_ids=ScopeIds(None, None, usage_key, usage_key),
field_data=DictFieldData(field_data),
)
@ddt.ddt
class HtmlModuleCourseApiTestCase(unittest.TestCase):
class HtmlBlockCourseApiTestCase(unittest.TestCase):
"""
Test the HTML XModule's student_view_data method.
"""
@@ -45,10 +45,9 @@ class HtmlModuleCourseApiTestCase(unittest.TestCase):
Ensure that student_view_data does not return html if the ENABLE_HTML_XBLOCK_STUDENT_VIEW_DATA feature flag
is not set.
"""
descriptor = Mock()
field_data = DictFieldData({'data': '<h1>Some HTML</h1>'})
module_system = get_test_system()
module = HtmlModule(descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
with override_settings(**settings):
self.assertEqual(module.student_view_data(), dict(
@@ -76,10 +75,9 @@ class HtmlModuleCourseApiTestCase(unittest.TestCase):
Note that the %%USER_ID%% substitution is tested below.
"""
descriptor = Mock()
field_data = DictFieldData({'data': html})
module_system = get_test_system()
module = HtmlModule(descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
self.assertEqual(module.student_view_data(), dict(enabled=True, html=html))
@ddt.data(
@@ -91,22 +89,20 @@ class HtmlModuleCourseApiTestCase(unittest.TestCase):
Ensure that student_view and public_view renders correctly.
"""
html = '<p>This is a test</p>'
descriptor = Mock()
field_data = DictFieldData({'data': html})
module_system = get_test_system()
module = HtmlModule(descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
rendered = module_system.render(module, view, {}).content
self.assertIn(html, rendered)
class HtmlModuleSubstitutionTestCase(unittest.TestCase):
descriptor = Mock()
class HtmlBlockSubstitutionTestCase(unittest.TestCase):
def test_substitution_works(self):
sample_xml = '''%%USER_ID%%'''
field_data = DictFieldData({'data': sample_xml})
module_system = get_test_system()
module = HtmlModule(self.descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
self.assertEqual(module.get_html(), str(module_system.anonymous_student_id))
def test_substitution_without_magic_string(self):
@@ -117,7 +113,7 @@ class HtmlModuleSubstitutionTestCase(unittest.TestCase):
'''
field_data = DictFieldData({'data': sample_xml})
module_system = get_test_system()
module = HtmlModule(self.descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
self.assertEqual(module.get_html(), sample_xml)
def test_substitution_without_anonymous_student_id(self):
@@ -125,13 +121,13 @@ class HtmlModuleSubstitutionTestCase(unittest.TestCase):
field_data = DictFieldData({'data': sample_xml})
module_system = get_test_system()
module_system.anonymous_student_id = None
module = HtmlModule(self.descriptor, module_system, field_data, Mock())
module = HtmlBlock(module_system, field_data, Mock())
self.assertEqual(module.get_html(), sample_xml)
class HtmlDescriptorIndexingTestCase(unittest.TestCase):
class HtmlBlockIndexingTestCase(unittest.TestCase):
"""
Make sure that HtmlDescriptor can format data for indexing as expected.
Make sure that HtmlBlock can format data for indexing as expected.
"""
def test_index_dictionary_simple_html_module(self):
@@ -221,9 +217,9 @@ class HtmlDescriptorIndexingTestCase(unittest.TestCase):
})
class CourseInfoModuleTestCase(unittest.TestCase):
class CourseInfoBlockTestCase(unittest.TestCase):
"""
Make sure that CourseInfoModule renders updates properly.
Make sure that CourseInfoBlock renders updates properly.
"""
def test_updates_render(self):
@@ -235,7 +231,7 @@ class CourseInfoModuleTestCase(unittest.TestCase):
"id": i,
"date": data,
"content": "This is a very important update!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
} for i, data in enumerate(
[
'January 1, 1970',
@@ -245,8 +241,7 @@ class CourseInfoModuleTestCase(unittest.TestCase):
]
)
]
info_module = CourseInfoModule(
Mock(),
info_module = CourseInfoBlock(
get_test_system(),
DictFieldData({'items': sample_update_data, 'data': ""}),
Mock()
@@ -256,7 +251,7 @@ class CourseInfoModuleTestCase(unittest.TestCase):
try:
info_module.get_html()
except ValueError:
self.fail("CourseInfoModule could not parse an invalid date!")
self.fail("CourseInfoBlock could not parse an invalid date!")
def test_updates_order(self):
"""
@@ -267,23 +262,22 @@ class CourseInfoModuleTestCase(unittest.TestCase):
"id": 3,
"date": "March 18, 1982",
"content": "This is a very important update that was inserted last with an older date!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
},
{
"id": 1,
"date": "January 1, 2012",
"content": "This is a very important update that was inserted first!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
},
{
"id": 2,
"date": "January 1, 2012",
"content": "This is a very important update that was inserted second!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
}
]
info_module = CourseInfoModule(
Mock(),
info_module = CourseInfoBlock(
Mock(),
DictFieldData({'items': sample_update_data, 'data': ""}),
Mock()
@@ -296,19 +290,19 @@ class CourseInfoModuleTestCase(unittest.TestCase):
"id": 2,
"date": "January 1, 2012",
"content": "This is a very important update that was inserted second!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
},
{
"id": 1,
"date": "January 1, 2012",
"content": "This is a very important update that was inserted first!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
},
{
"id": 3,
"date": "March 18, 1982",
"content": "This is a very important update that was inserted last with an older date!",
"status": CourseInfoModule.STATUS_VISIBLE,
"status": CourseInfoBlock.STATUS_VISIBLE,
}
],
'hidden_updates': [],

View File

@@ -320,7 +320,7 @@ class TestLibraryContentModuleWithSearchIndex(LibraryContentModuleTestMixin, Lib
@patch(
'xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render
)
@patch('xmodule.html_module.HtmlModule.author_view', dummy_render, create=True)
@patch('xmodule.html_module.HtmlBlock.author_view', dummy_render, create=True)
@patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: [])
class TestLibraryContentRender(LibraryContentTest):
"""

View File

@@ -19,8 +19,8 @@ dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-
@patch(
'xmodule.modulestore.split_mongo.caching_descriptor_system.CachingDescriptorSystem.render', VanillaRuntime.render
)
@patch('xmodule.html_module.HtmlDescriptor.author_view', dummy_render, create=True)
@patch('xmodule.html_module.HtmlDescriptor.has_author_view', True, create=True)
@patch('xmodule.html_module.HtmlBlock.author_view', dummy_render, create=True)
@patch('xmodule.html_module.HtmlBlock.has_author_view', True, create=True)
@patch('xmodule.x_module.DescriptorSystem.applicable_aside_types', lambda self, block: [])
class TestLibraryRoot(MixedSplitTestCase):
"""

View File

@@ -168,9 +168,9 @@ class SplitTestModuleLMSTest(SplitTestModuleTest):
)
# Patch the definition_to_xml for the html children.
@patch('xmodule.html_module.HtmlDescriptor.definition_to_xml')
@patch('xmodule.html_module.HtmlBlock.definition_to_xml')
def test_export_import_round_trip(self, def_to_xml):
# The HtmlDescriptor definition_to_xml tries to write to the filesystem
# The HtmlBlock definition_to_xml tries to write to the filesystem
# before returning an xml object. Patch this to just return the xml.
def_to_xml.return_value = lxml.etree.Element('html')

View File

@@ -33,7 +33,7 @@ from xblock.fields import ScopeIds
from xmodule.annotatable_module import AnnotatableDescriptor
from xmodule.conditional_module import ConditionalDescriptor
from xmodule.course_module import CourseDescriptor
from xmodule.html_module import HtmlDescriptor
from xmodule.html_module import HtmlBlock
from xmodule.poll_module import PollDescriptor
from xmodule.randomize_module import RandomizeDescriptor
from xmodule.seq_module import SequenceDescriptor
@@ -56,7 +56,7 @@ from xmodule.x_module import (
# TODO: Add more types of sample data
LEAF_XMODULES = {
AnnotatableDescriptor: [{}],
HtmlDescriptor: [{}],
HtmlBlock: [{}],
PollDescriptor: [{'display_name': 'Poll Display Name'}],
WordCloudDescriptor: [{}],
}
@@ -136,7 +136,7 @@ class ContainerModuleRuntimeFactory(ModuleSystemFactory):
"""
# pylint: disable=no-member
if depth == 0:
self.get_module.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlDescriptor)
self.get_module.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlBlock)
else:
self.get_module.side_effect = lambda x: ContainerModuleFactory(
descriptor_cls=VerticalBlock,
@@ -164,7 +164,7 @@ class ContainerDescriptorRuntimeFactory(DescriptorSystemFactory):
"""
# pylint: disable=no-member
if depth == 0:
self.load_item.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlDescriptor)
self.load_item.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlBlock)
else:
self.load_item.side_effect = lambda x: ContainerModuleFactory(
descriptor_cls=VerticalBlock,

View File

@@ -213,8 +213,8 @@ class ContainerPage(PageObject, HelpMixin):
Returns:
list: A list containing inner HTMl
"""
self.wait_for_element_visibility('.xmodule_HtmlModule', 'Xblock content is visible')
html = self.q(css='.xmodule_HtmlModule').html
self.wait_for_element_visibility('.xmodule_HtmlBlock', 'Xblock content is visible')
html = self.q(css='.xmodule_HtmlBlock').html
html = html[0].strip()
return html

View File

@@ -94,7 +94,7 @@ class PagesPage(CoursePage):
'.wrapper-component-action-header .component-actions',
"Tab's edit button is visible"
)
return self.q(css='div.xmodule_StaticTabModule').text
return self.q(css='div.xmodule_StaticTabBlock').text
@property
def built_in_page_titles(self):

View File

@@ -58,7 +58,7 @@ class CopiedFromLmsBadContentTest(BadComponentTest):
Return the "bad" HTML content that has been problematic for Studio.
"""
return """
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlModule xblock-initialized"
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlBlock xblock-initialized"
data-runtime-class="LmsRuntime" data-init="XBlockToXModuleShim" data-block-type="html"
data-runtime-version="1" data-type="HTMLModule" data-course-id="GeorgetownX/HUMW-421-01"
data-request-token="thisIsNotARealRequestToken"
@@ -81,7 +81,7 @@ class CopiedFromStudioBadContentTest(BadComponentTest):
<ol class="components ui-sortable">
<li class="component" data-locator="i4x://Wellesley_College/100/html/6390f1fd3fe640d49580b8415fe1330b"
data-course-key="Wellesley_College/100/2014_Summer">
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlModule xblock-initialized"
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlBlock xblock-initialized"
data-runtime-class="PreviewRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1"
data-request-token="thisIsNotARealRequestToken"
data-usage-id="i4x://Wellesley_College/100/html/6390f1fd3fe640d49580b8415fe1330b"

View File

@@ -49,9 +49,7 @@ class StudentViewTransformer(BlockStructureTransformer):
# problem where your particular XModule explodes here (and don't
# have the time to convert it to an XBlock), please try refactoring
# so that you declare your student_view() method in a common
# ancestor class of both your Descriptor and Module classes. As an
# example, I changed the name of HtmlFields to HtmlBlock and moved
# student_view() from HtmlModuleMixin to HtmlBlock.
# ancestor class of both your Descriptor and Module classes.
student_view = getattr(block.__class__, 'student_view', None)
supports_multi_device = block.has_support(student_view, 'multi_device')

View File

@@ -66,6 +66,7 @@ from student.models import CourseEnrollment, anonymous_id_for_user
from verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
from xblock_django.models import XBlockConfiguration
from xmodule.capa_module import ProblemBlock
from xmodule.html_module import AboutBlock, CourseInfoBlock, HtmlBlock, StaticTabBlock
from xmodule.lti_module import LTIDescriptor
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
@@ -1524,7 +1525,7 @@ class TestHtmlModifiers(ModuleStoreTestCase):
)
result_fragment = module.render(STUDENT_VIEW)
self.assertEquals(len(PyQuery(result_fragment.content)('div.xblock.xblock-student_view.xmodule_HtmlModule')), 1)
self.assertEquals(len(PyQuery(result_fragment.content)('div.xblock.xblock-student_view.xmodule_HtmlBlock')), 1)
def test_xmodule_display_wrapper_disabled(self):
module = render.get_module(
@@ -1536,7 +1537,7 @@ class TestHtmlModifiers(ModuleStoreTestCase):
)
result_fragment = module.render(STUDENT_VIEW)
self.assertNotIn('div class="xblock xblock-student_view xmodule_display xmodule_HtmlModule"',
self.assertNotIn('div class="xblock xblock-student_view xmodule_display xmodule_HtmlBlock"',
result_fragment.content)
def test_static_link_rewrite(self):
@@ -1933,7 +1934,11 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
PER_COURSE_ANONYMIZED_DESCRIPTORS = (LTIDescriptor, )
PER_STUDENT_ANONYMIZED_XBLOCKS = [
AboutBlock,
CourseInfoBlock,
HtmlBlock,
ProblemBlock,
StaticTabBlock,
VideoBlock,
]

View File

@@ -25,7 +25,7 @@ def edxnotes(cls):
# Import is placed here to avoid model import at project startup.
from edxnotes.helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled
is_studio = getattr(self.system, "is_author_mode", False)
course = self.descriptor.runtime.modulestore.get_course(self.runtime.course_id)
course = getattr(self, 'descriptor', self).runtime.modulestore.get_course(self.runtime.course_id)
# Must be disabled when:
# - in Studio

View File

@@ -58,7 +58,7 @@ from shoppingcart.models import Coupon, CourseRegCodeItem, PaidCourseRegistratio
from student.models import CourseEnrollment
from student.roles import CourseFinanceAdminRole, CourseInstructorRole, CourseSalesAdminRole, CourseStaffRole
from util.json_request import JsonResponse
from xmodule.html_module import HtmlDescriptor
from xmodule.html_module import HtmlBlock
from xmodule.modulestore.django import modulestore
from xmodule.tabs import CourseTab
@@ -714,7 +714,7 @@ def _section_data_download(course, access):
def null_applicable_aside_types(block): # pylint: disable=unused-argument
"""
get_aside method for monkey-patching into applicable_aside_types
while rendering an HtmlDescriptor for email text editing. This returns
while rendering an HtmlBlock for email text editing. This returns
an empty list.
"""
return []
@@ -726,8 +726,8 @@ def _section_send_email(course, access):
# Monkey-patch applicable_aside_types to return no asides for the duration of this render
with patch.object(course.runtime, 'applicable_aside_types', null_applicable_aside_types):
# This HtmlDescriptor is only being used to generate a nice text editor.
html_module = HtmlDescriptor(
# This HtmlBlock is only being used to generate a nice text editor.
html_module = HtmlBlock(
course.system,
DictFieldData({'data': ''}),
ScopeIds(None, None, None, course_key.make_usage_key('html', 'fake'))

View File

@@ -11,7 +11,7 @@ from six.moves import range
from mobile_api.testutils import MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin
from mobile_api.utils import API_V1, API_V05
from xmodule.html_module import CourseInfoModule
from xmodule.html_module import CourseInfoBlock
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.xml_importer import import_course_from_xml
@@ -60,7 +60,7 @@ class TestUpdates(MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTest
"id": num,
"date": "Date" + str(num),
"content": "<a href=\"/static/\">Update" + str(num) + "</a>",
"status": CourseInfoModule.STATUS_VISIBLE
"status": CourseInfoBlock.STATUS_VISIBLE
}
)
else: