From dbc99ef8ad89b7210c8a5bea80a55e7aad26ad0e Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 13 Feb 2014 09:53:32 -0500 Subject: [PATCH] Implement children for pure XBlocks in edx-platform This requires fixing the javascript api implementation, and adding an implementation of get_block to the ModuleSystem api. However, the implementation is incomplete, due to mismatches between the expectations of XModule and XBlock. Also adds tests using the Acid block to make sure that the javascript and python apis for children are working correctly. --- cms/djangoapps/contentstore/views/preview.py | 3 +- .../coffee/src/xblock/cms.runtime.v1.coffee | 4 +- common/lib/xmodule/xmodule/tests/__init__.py | 1 + common/lib/xmodule/xmodule/x_module.py | 7 +- .../coffee/spec/xblock/core_spec.coffee | 4 +- .../coffee/spec/xblock/runtime.v1_spec.coffee | 9 +- common/static/coffee/src/xblock/core.coffee | 3 +- .../coffee/src/xblock/runtime.v1.coffee | 8 +- common/test/acceptance/pages/studio/unit.py | 38 ++++--- common/test/acceptance/pages/xblock/acid.py | 10 ++ common/test/acceptance/tests/test_lms.py | 88 +++++++++++---- common/test/acceptance/tests/test_studio.py | 106 ++++++++++++++---- lms/djangoapps/courseware/module_render.py | 6 +- .../courseware/tests/test_module_render.py | 4 + .../open_ended_notifications.py | 2 + .../staff_grading_service.py | 1 + lms/djangoapps/open_ended_grading/tests.py | 1 + lms/djangoapps/open_ended_grading/utils.py | 1 + lms/lib/xblock/test/test_runtime.py | 1 + .../coffee/src/xblock/lms.runtime.v1.coffee | 4 +- requirements/edx/github.txt | 4 +- 21 files changed, 228 insertions(+), 77 deletions(-) diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 28b81316ad..33951a6089 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -131,6 +131,7 @@ def _preview_module_system(request, descriptor): # get_user_role accepts a location or a CourseLocator. # If descriptor.location is a CourseLocator, course_id is unused. get_user_role=lambda: get_user_role(request.user, descriptor.location, course_id), + descriptor_runtime=descriptor.runtime, ) @@ -158,6 +159,6 @@ def get_preview_fragment(request, descriptor): try: fragment = module.render("student_view") except Exception as exc: # pylint: disable=W0703 - log.debug("Unable to render student_view for %r", module, exc_info=True) + log.warning("Unable to render student_view for %r", module, exc_info=True) fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)})) return fragment diff --git a/cms/static/coffee/src/xblock/cms.runtime.v1.coffee b/cms/static/coffee/src/xblock/cms.runtime.v1.coffee index 4eddd6ef3a..b420a6f33c 100644 --- a/cms/static/coffee/src/xblock/cms.runtime.v1.coffee +++ b/cms/static/coffee/src/xblock/cms.runtime.v1.coffee @@ -3,7 +3,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) -> class PreviewRuntime.v1 extends XBlock.Runtime.v1 handlerUrl: (element, handlerName, suffix, query, thirdparty) -> - uri = URI("/preview/xblock").segment($(@element).data('usage-id')) + uri = URI("/preview/xblock").segment($(element).data('usage-id')) .segment('handler') .segment(handlerName) if suffix? then uri.segment(suffix) @@ -14,7 +14,7 @@ define ["jquery", "xblock/runtime.v1", "URI"], ($, XBlock, URI) -> class StudioRuntime.v1 extends XBlock.Runtime.v1 handlerUrl: (element, handlerName, suffix, query, thirdparty) -> - uri = URI("/xblock").segment($(@element).data('usage-id')) + uri = URI("/xblock").segment($(element).data('usage-id')) .segment('handler') .segment(handlerName) if suffix? then uri.segment(suffix) diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py index 28e612926a..4dce45af91 100644 --- a/common/lib/xmodule/xmodule/tests/__init__.py +++ b/common/lib/xmodule/xmodule/tests/__init__.py @@ -78,6 +78,7 @@ def get_test_system(course_id=''): course_id=course_id, error_descriptor_class=ErrorDescriptor, get_user_role=Mock(is_staff=False), + descriptor_runtime=get_test_descriptor_system(), ) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 484f0c9032..a136edcdaf 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1048,7 +1048,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs """ def __init__( self, static_url, track_function, get_module, render_template, - replace_urls, user=None, filestore=None, + replace_urls, descriptor_runtime, user=None, filestore=None, debug=False, hostname="", xqueue=None, publish=None, node_path="", anonymous_student_id='', course_id=None, open_ended_grading_interface=None, s3_interface=None, @@ -1089,6 +1089,8 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs that capa_module can use to fix up the static urls in ajax results. + descriptor_runtime - A `DescriptorSystem` to use for loading xblocks by id + anonymous_student_id - Used for tracking modules with student id course_id - the course_id containing this module @@ -1148,6 +1150,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs self.get_real_user = get_real_user self.get_user_role = get_user_role + self.descriptor_runtime = descriptor_runtime def get(self, attr): """ provide uniform access to attributes (like etree).""" @@ -1172,7 +1175,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs return self.handler_url(self.xmodule_instance, 'xmodule_handler', '', '').rstrip('/?') def get_block(self, block_id): - raise NotImplementedError("XModules must use get_module to load other modules") + return self.get_module(self.descriptor_runtime.get_block(block_id)) def resource_url(self, resource): raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls") diff --git a/common/static/coffee/spec/xblock/core_spec.coffee b/common/static/coffee/spec/xblock/core_spec.coffee index efc6d15807..c71905b5a2 100644 --- a/common/static/coffee/spec/xblock/core_spec.coffee +++ b/common/static/coffee/spec/xblock/core_spec.coffee @@ -31,8 +31,8 @@ describe "XBlock", -> @missingInitBlock = XBlock.initializeBlock($('#missing-init')[0]) it "loads the right runtime version", -> - expect(TestRuntime.vA).toHaveBeenCalledWith($('#vA')[0], @fakeChildren) - expect(TestRuntime.vZ).toHaveBeenCalledWith($('#vZ')[0], @fakeChildren) + expect(TestRuntime.vA).toHaveBeenCalledWith() + expect(TestRuntime.vZ).toHaveBeenCalledWith() it "loads the right init function", -> expect(window.initFnA).toHaveBeenCalledWith(@runtimeA, $('#vA')[0]) diff --git a/common/static/coffee/spec/xblock/runtime.v1_spec.coffee b/common/static/coffee/spec/xblock/runtime.v1_spec.coffee index f13d69154c..7bad77494d 100644 --- a/common/static/coffee/spec/xblock/runtime.v1_spec.coffee +++ b/common/static/coffee/spec/xblock/runtime.v1_spec.coffee @@ -9,12 +9,13 @@ describe "XBlock.Runtime.v1", -> ] @element = $('.xblock')[0] + $(@element).prop('xblock_children', @children) - @runtime = new XBlock.Runtime.v1(@element, @children) + @runtime = new XBlock.Runtime.v1(@element) it "provides a list of children", -> - expect(@runtime.children).toBe(@children) + expect(@runtime.children(@element)).toBe(@children) it "maps children by name", -> - expect(@runtime.childMap.childA).toBe(@children[0]) - expect(@runtime.childMap.childB).toBe(@children[1]) + expect(@runtime.childMap(@element, 'childA')).toBe(@children[0]) + expect(@runtime.childMap(@element, 'childB')).toBe(@children[1]) diff --git a/common/static/coffee/src/xblock/core.coffee b/common/static/coffee/src/xblock/core.coffee index 9c5cc0961c..72768cac63 100644 --- a/common/static/coffee/src/xblock/core.coffee +++ b/common/static/coffee/src/xblock/core.coffee @@ -7,8 +7,9 @@ runtime = $element.data("runtime-class") version = $element.data("runtime-version") initFnName = $element.data("init") + $element.prop('xblock_children', children) if runtime? and version? and initFnName? - runtime = new window[runtime]["v#{version}"](element, children) + runtime = new window[runtime]["v#{version}"] initFn = window[initFnName] block = initFn(runtime, element) ? {} else diff --git a/common/static/coffee/src/xblock/runtime.v1.coffee b/common/static/coffee/src/xblock/runtime.v1.coffee index b3f28242ab..e7955306be 100644 --- a/common/static/coffee/src/xblock/runtime.v1.coffee +++ b/common/static/coffee/src/xblock/runtime.v1.coffee @@ -1,5 +1,5 @@ class XBlock.Runtime.v1 - constructor: (@element, @children) -> - @childMap = {} - $.each @children, (idx, child) => - @childMap[child.name] = child + children: (block) => $(block).prop('xblock_children') + childMap: (block, childName) => + for child in @children(block) + return child if child.name == childName \ No newline at end of file diff --git a/common/test/acceptance/pages/studio/unit.py b/common/test/acceptance/pages/studio/unit.py index e082d23d8d..9be786bcde 100644 --- a/common/test/acceptance/pages/studio/unit.py +++ b/common/test/acceptance/pages/studio/unit.py @@ -4,7 +4,7 @@ Unit page in Studio from bok_choy.page_object import PageObject from bok_choy.query import SubQuery -from bok_choy.promise import Promise, EmptyPromise, fulfill +from bok_choy.promise import EmptyPromise, fulfill from . import BASE_URL @@ -24,20 +24,32 @@ class UnitPage(PageObject): return "{}/unit/{}".format(BASE_URL, self.unit_locator) def is_browser_on_page(self): - return self.is_css_present('body.view-unit') + # Wait until all components have been loaded + return ( + self.is_css_present('body.view-unit') and + len(self.q(css=Component.BODY_SELECTOR)) == len(self.q(css='{} .xblock-student_view'.format(Component.BODY_SELECTOR))) + ) - def component(self, title): - return Component(self.browser, self._locator(title)) + @property + def components(self): + """ + Return a list of components loaded on the unit page. + """ + return self.q(css=Component.BODY_SELECTOR).map(lambda el: Component(self.browser, el['data-locator'])).results - def _locator(self, title): - def _check_func(): - locators = self.q(css=Component.BODY_SELECTOR).filter( - SubQuery(css=Component.NAME_SELECTOR).filter(text=title) - ).map(lambda el: el['data-locator']).results - - return (len(locators) > 0, locators[0]) - - return fulfill(Promise(_check_func, "Found data locator for component")) + def edit_draft(self): + """ + Started editing a draft of this unit. + """ + fulfill(EmptyPromise( + lambda: self.q(css='.create-draft').present, + 'Wait for edit draft link to be present' + )) + self.q(css='.create-draft').click() + fulfill(EmptyPromise( + lambda: self.q(css='.editing-draft-alert').present, + 'Wait for draft mode to be activated' + )) class Component(PageObject): diff --git a/common/test/acceptance/pages/xblock/acid.py b/common/test/acceptance/pages/xblock/acid.py index add30c3b91..4aa54e458c 100644 --- a/common/test/acceptance/pages/xblock/acid.py +++ b/common/test/acceptance/pages/xblock/acid.py @@ -51,6 +51,16 @@ class AcidView(PageObject): """ return self.test_passed('.document-ready-run') + @property + def child_tests_passed(self): + """ + Whether the tests of children passed + """ + return all([ + self.test_passed('.child-counts-match'), + self.test_passed('.child-values-match') + ]) + def scope_passed(self, scope): return all( self.test_passed('.scope-storage-test.scope-{} {}'.format(scope, test)) diff --git a/common/test/acceptance/tests/test_lms.py b/common/test/acceptance/tests/test_lms.py index bbad1ba4c9..2f0946f4c2 100644 --- a/common/test/acceptance/tests/test_lms.py +++ b/common/test/acceptance/tests/test_lms.py @@ -3,7 +3,7 @@ E2E tests for the LMS. """ -from unittest import skip +from unittest import skip, expectedFailure from bok_choy.web_app_test import WebAppTest from bok_choy.promise import EmptyPromise, fulfill_before, fulfill, Promise @@ -292,8 +292,9 @@ class VideoTest(UniqueCourseTest): course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( - XBlockFixtureDesc('video', 'Video') - ))).install() + XBlockFixtureDesc('vertical', 'Test Unit').add_children( + XBlockFixtureDesc('video', 'Video') + )))).install() # Auto-auth register for the course @@ -338,18 +339,48 @@ class VideoTest(UniqueCourseTest): self.assertGreaterEqual(self.video.duration, self.video.elapsed_time) -class XBlockAcidTest(UniqueCourseTest): +class XBlockAcidBase(UniqueCourseTest): """ - Tests that verify that XBlock integration is working correctly + Base class for tests that verify that XBlock integration is working correctly """ + __test__ = False def setUp(self): """ Create a unique identifier for the course used in this test. """ # Ensure that the superclass sets up - super(XBlockAcidTest, self).setUp() + super(XBlockAcidBase, self).setUp() + self.setup_fixtures() + + AutoAuthPage(self.browser, course_id=self.course_id).visit() + + self.course_info_page = CourseInfoPage(self.browser, self.course_id) + self.tab_nav = TabNavPage(self.browser) + + def test_acid_block(self): + """ + Verify that all expected acid block tests pass in the lms. + """ + + self.course_info_page.visit() + self.tab_nav.go_to_tab('Courseware') + + acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]') + self.assertTrue(acid_block.init_fn_passed) + self.assertTrue(acid_block.doc_ready_passed) + self.assertTrue(acid_block.child_tests_passed) + self.assertTrue(acid_block.scope_passed('user_state')) + + +class XBlockAcidNoChildTest(XBlockAcidBase): + """ + Tests of an AcidBlock with no children + """ + __test__ = True + + def setup_fixtures(self): course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], @@ -360,24 +391,43 @@ class XBlockAcidTest(UniqueCourseTest): course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( - XBlockFixtureDesc('acid', 'Acid Block') + XBlockFixtureDesc('vertical', 'Test Unit').add_children( + XBlockFixtureDesc('acid', 'Acid Block') + ) ) ) ).install() - AutoAuthPage(self.browser, course_id=self.course_id).visit() - self.course_info_page = CourseInfoPage(self.browser, self.course_id) - self.tab_nav = TabNavPage(self.browser) +class XBlockAcidChildTest(XBlockAcidBase): + """ + Tests of an AcidBlock with children + """ + __test__ = True - self.course_info_page.visit() - self.tab_nav.go_to_tab('Courseware') + def setup_fixtures(self): + course_fix = CourseFixture( + self.course_info['org'], + self.course_info['number'], + self.course_info['run'], + self.course_info['display_name'] + ) + course_fix.add_children( + XBlockFixtureDesc('chapter', 'Test Section').add_children( + XBlockFixtureDesc('sequential', 'Test Subsection').add_children( + XBlockFixtureDesc('vertical', 'Test Unit').add_children( + XBlockFixtureDesc('acid', 'Acid Block').add_children( + XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}), + XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}), + XBlockFixtureDesc('html', 'Html Child', data="Contents"), + ) + ) + ) + ) + ).install() + + # This will fail until we fix support of children in pure XBlocks + @expectedFailure def test_acid_block(self): - """ - Verify that all expected acid block tests pass in the lms. - """ - acid_block = AcidView(self.browser, '.xblock-student_view[data-block-type=acid]') - self.assertTrue(acid_block.init_fn_passed) - self.assertTrue(acid_block.doc_ready_passed) - self.assertTrue(acid_block.scope_passed('user_state')) + super(XBlockAcidChildTest, self).test_acid_block() diff --git a/common/test/acceptance/tests/test_studio.py b/common/test/acceptance/tests/test_studio.py index 989533145d..17bfc0a75c 100644 --- a/common/test/acceptance/tests/test_studio.py +++ b/common/test/acceptance/tests/test_studio.py @@ -1,6 +1,8 @@ """ Acceptance tests for Studio. """ +from unittest import expectedFailure + from bok_choy.web_app_test import WebAppTest from ..pages.studio.asset_index import AssetIndexPage @@ -110,17 +112,18 @@ class CoursePagesTest(UniqueCourseTest): page.visit() -class XBlockAcidTest(WebAppTest): +class XBlockAcidBase(WebAppTest): """ - Tests that verify that XBlock integration is working correctly + Base class for tests that verify that XBlock integration is working correctly """ + __test__ = False def setUp(self): """ Create a unique identifier for the course used in this test. """ # Ensure that the superclass sets up - super(XBlockAcidTest, self).setUp() + super(XBlockAcidBase, self).setUp() # Define a unique course identifier self.course_info = { @@ -140,6 +143,50 @@ class XBlockAcidTest(WebAppTest): self.course_id = '{org}.{number}.{run}'.format(**self.course_info) + self.setup_fixtures() + + self.auth_page.visit() + + def test_acid_block_preview(self): + """ + Verify that all expected acid block tests pass in studio preview + """ + + self.outline.visit() + unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to() + + acid_block = AcidView(self.browser, unit.components[0].preview_selector) + self.assertTrue(acid_block.init_fn_passed) + self.assertTrue(acid_block.doc_ready_passed) + self.assertTrue(acid_block.child_tests_passed) + self.assertTrue(acid_block.scope_passed('user_state')) + + def test_acid_block_editor(self): + """ + Verify that all expected acid block tests pass in studio preview + """ + + self.outline.visit() + unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to() + + unit.edit_draft() + + acid_block = AcidView(self.browser, unit.components[0].edit().editor_selector) + self.assertTrue(acid_block.init_fn_passed) + self.assertTrue(acid_block.doc_ready_passed) + self.assertTrue(acid_block.child_tests_passed) + self.assertTrue(acid_block.scope_passed('content')) + self.assertTrue(acid_block.scope_passed('settings')) + + +class XBlockAcidNoChildTest(XBlockAcidBase): + """ + Tests of an AcidBlock with no children + """ + __test__ = True + + def setup_fixtures(self): + course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], @@ -157,27 +204,42 @@ class XBlockAcidTest(WebAppTest): ) ).install() - self.auth_page.visit() - self.outline.visit() - unit = self.outline.section('Test Section').subsection('Test Subsection').toggle_expand().unit('Test Unit').go_to() - self.acid_component = unit.component('Acid Block') +class XBlockAcidChildTest(XBlockAcidBase): + """ + Tests of an AcidBlock with children + """ + __test__ = True + def setup_fixtures(self): + + course_fix = CourseFixture( + self.course_info['org'], + self.course_info['number'], + self.course_info['run'], + self.course_info['display_name'] + ) + + course_fix.add_children( + XBlockFixtureDesc('chapter', 'Test Section').add_children( + XBlockFixtureDesc('sequential', 'Test Subsection').add_children( + XBlockFixtureDesc('vertical', 'Test Unit').add_children( + XBlockFixtureDesc('acid', 'Acid Block').add_children( + XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}), + XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}), + XBlockFixtureDesc('html', 'Html Child', data="Contents"), + ) + ) + ) + ) + ).install() + + # This will fail until we fix support of children in pure XBlocks + @expectedFailure def test_acid_block_preview(self): - """ - Verify that all expected acid block tests pass in studio preview - """ - acid_block = AcidView(self.browser, self.acid_component.preview_selector) - self.assertTrue(acid_block.init_fn_passed) - self.assertTrue(acid_block.doc_ready_passed) - self.assertTrue(acid_block.scope_passed('user_state')) + super(XBlockAcidChildTest, self).test_acid_block_preview() + # This will fail until we fix support of children in pure XBlocks + @expectedFailure def test_acid_block_editor(self): - """ - Verify that all expected acid block tests pass in studio preview - """ - acid_block = AcidView(self.browser, self.acid_component.edit().editor_selector) - self.assertTrue(acid_block.init_fn_passed) - self.assertTrue(acid_block.doc_ready_passed) - self.assertTrue(acid_block.scope_passed('content')) - self.assertTrue(acid_block.scope_passed('settings')) + super(XBlockAcidChildTest, self).test_acid_block_editor() diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 382131f262..f636ccea7c 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -227,7 +227,6 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours return None student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache)) - descriptor._field_data = LmsFieldData(descriptor._field_data, student_data) def make_xqueue_callback(dispatch='score_update'): @@ -433,6 +432,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours 'i18n': ModuleI18nService(), }, get_user_role=lambda: get_user_role(user, course_id), + descriptor_runtime=descriptor.runtime, ) # pass position specified in URL to module through ModuleSystem @@ -451,8 +451,8 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours else: system.error_descriptor_class = NonStaffErrorDescriptor - descriptor.xmodule_runtime = system - descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id) + descriptor.bind_for_student(system, LmsFieldData(descriptor._field_data, student_data)) # pylint: disable=protected-access + descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id) # pylint: disable=protected-access return descriptor diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 0dd527ed2b..8c7357087b 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -2,6 +2,7 @@ Test for lms courseware app, module render unit """ from ddt import ddt, data +from functools import partial from mock import MagicMock, patch, Mock import json @@ -657,6 +658,9 @@ class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase): ), scope_ids=Mock(spec=ScopeIds), ) + # Use the xblock_class's bind_for_student method + descriptor.bind_for_student = partial(xblock_class.bind_for_student, descriptor) + if hasattr(xblock_class, 'module_class'): descriptor.module_class = xblock_class.module_class diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 9398a11957..4962f8efa9 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -69,6 +69,7 @@ def peer_grading_notifications(course, user): get_module=None, render_template=render_to_string, replace_urls=None, + descriptor_runtime=None, ) peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system) pending_grading = False @@ -129,6 +130,7 @@ def combined_notifications(course, user): get_module=None, render_template=render_to_string, replace_urls=None, + descriptor_runtime=None, ) #Initialize controller query service using our mock system controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system) diff --git a/lms/djangoapps/open_ended_grading/staff_grading_service.py b/lms/djangoapps/open_ended_grading/staff_grading_service.py index 81a2eb401c..dad93fbc28 100644 --- a/lms/djangoapps/open_ended_grading/staff_grading_service.py +++ b/lms/djangoapps/open_ended_grading/staff_grading_service.py @@ -83,6 +83,7 @@ class StaffGradingService(GradingService): get_module=None, render_template=render_to_string, replace_urls=None, + descriptor_runtime=None, ) super(StaffGradingService, self).__init__(config) self.url = config['url'] + config['staff_grading'] diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index 517d3d8824..8ac9bab50f 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -285,6 +285,7 @@ class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase): open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE, mixins=settings.XBLOCK_MIXINS, error_descriptor_class=ErrorDescriptor, + descriptor_runtime=None, ) self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system, field_data, ScopeIds(None, None, None, None)) self.descriptor.xmodule_runtime = self.system diff --git a/lms/djangoapps/open_ended_grading/utils.py b/lms/djangoapps/open_ended_grading/utils.py index 01d58fb479..9f60289a2d 100644 --- a/lms/djangoapps/open_ended_grading/utils.py +++ b/lms/djangoapps/open_ended_grading/utils.py @@ -33,6 +33,7 @@ SYSTEM = LmsModuleSystem( get_module=None, render_template=render_to_string, replace_urls=None, + descriptor_runtime=None, ) diff --git a/lms/lib/xblock/test/test_runtime.py b/lms/lib/xblock/test/test_runtime.py index 14987a87d3..63fd2fe763 100644 --- a/lms/lib/xblock/test/test_runtime.py +++ b/lms/lib/xblock/test/test_runtime.py @@ -48,6 +48,7 @@ class TestHandlerUrl(TestCase): render_template=Mock(), replace_urls=str, course_id=self.course_id, + descriptor_runtime=Mock(), ) def test_trailing_characters(self): diff --git a/lms/static/coffee/src/xblock/lms.runtime.v1.coffee b/lms/static/coffee/src/xblock/lms.runtime.v1.coffee index 9a999727a3..f10b1ae1c5 100644 --- a/lms/static/coffee/src/xblock/lms.runtime.v1.coffee +++ b/lms/static/coffee/src/xblock/lms.runtime.v1.coffee @@ -2,8 +2,8 @@ class LmsRuntime.v1 extends XBlock.Runtime.v1 handlerUrl: (element, handlerName, suffix, query, thirdparty) -> - courseId = $(@element).data("course-id") - usageId = $(@element).data("usage-id") + courseId = $(element).data("course-id") + usageId = $(element).data("usage-id") handlerAuth = if thirdparty then "handler_noauth" else "handler" uri = URI('/courses').segment(courseId) diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index f08722afed..c8cb2c4897 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -21,6 +21,6 @@ -e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool -e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle -e git+https://github.com/edx/event-tracking.git@f0211d702d#egg=event-tracking --e git+https://github.com/edx/bok-choy.git@v0.2.1#egg=bok_choy +-e git+https://github.com/edx/bok-choy.git@62de7b576a08f36cde5b030c52bccb1a2f3f8df1#egg=bok_choy -e git+https://github.com/edx-solutions/django-splash.git@15bf143b15714e22fc451ff1b0f8a7a2a9483172#egg=django-splash --e git+https://github.com/edx/acid-block.git@aa95a3c#egg=acid-xblock +-e git+https://github.com/edx/acid-block.git@9c832513f0c01f79227bea894fba11c66fe4c08c#egg=acid-xblock