diff --git a/cms/djangoapps/contentstore/tasks.py b/cms/djangoapps/contentstore/tasks.py index eb249d9e788..d17dc30a04f 100644 --- a/cms/djangoapps/contentstore/tasks.py +++ b/cms/djangoapps/contentstore/tasks.py @@ -1198,13 +1198,16 @@ def _scan_course_for_links(course_key): blocks.extend(vertical.get_children()) for block in blocks: - block_id = str(block.usage_key) - if block.category != 'drag-and-drop-v2': - block_info = get_block_info(block) - block_data = block_info['data'] + # Excluding 'drag-and-drop-v2' as it contains data of object type instead of string, causing errors, + # and it doesn't contain user-facing links to scan. + if block.category == 'drag-and-drop-v2': + continue - url_list = _get_urls(block_data) - urls_to_validate += [[block_id, url] for url in url_list] + block_id = str(block.usage_key) + block_info = get_block_info(block) + block_data = block_info['data'] + url_list = _get_urls(block_data) + urls_to_validate += [[block_id, url] for url in url_list] return urls_to_validate diff --git a/cms/djangoapps/contentstore/tests/test_tasks.py b/cms/djangoapps/contentstore/tests/test_tasks.py index 4a31bb3b669..edd6bb19934 100644 --- a/cms/djangoapps/contentstore/tests/test_tasks.py +++ b/cms/djangoapps/contentstore/tests/test_tasks.py @@ -29,7 +29,7 @@ from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, ModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order +from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory # lint-amnesty, pylint: disable=wrong-import-order from ..tasks import ( export_olx, update_special_exams_and_publish, @@ -365,6 +365,45 @@ def test_number_of_scanned_blocks_equals_blocks_in_course(self, mock_get_urls): _scan_course_for_links(self.test_course.id) self.assertEqual(len(expected_blocks), mock_get_urls.call_count) + @mock.patch('cms.djangoapps.contentstore.tasks.get_block_info', autospec=True) + @mock.patch('cms.djangoapps.contentstore.tasks.modulestore', autospec=True) + def test_scan_course_excludes_drag_and_drop(self, mock_modulestore, mock_get_block_info): + """ + Test that `_scan_course_for_links` excludes blocks of category 'drag-and-drop-v2'. + """ + + vertical = BlockFactory.create( + category='vertical', + parent_location=self.test_course.location + ) + drag_and_drop_block = BlockFactory.create( + category='drag-and-drop-v2', + parent_location=vertical.location, + ) + text_block = BlockFactory.create( + category='html', + parent_location=vertical.location, + data='Test Link -> Example.com' + ) + + mock_modulestore_instance = mock.Mock() + mock_modulestore.return_value = mock_modulestore_instance + mock_modulestore_instance.get_items.return_value = [vertical] + vertical.get_children = mock.Mock(return_value=[drag_and_drop_block, text_block]) + + def get_block_side_effect(block): + block_data = getattr(block, 'data') + if isinstance(block_data, str): + return {'data' : block_data} + raise TypeError("expected string or bytes-like object, got 'dict'") + mock_get_block_info.side_effect = get_block_side_effect + + urls = _scan_course_for_links(self.test_course.id) + + # The drag-and-drop block should not appear in the results + assert all(block_id != str(drag_and_drop_block.usage_key) for block_id, _ in urls), "Drag and Drop blocks should be excluded" + assert any(block_id == str(text_block.usage_key) for block_id, _ in urls), "Text block should be included" + @pytest.mark.asyncio async def test_every_detected_link_is_validated(self): '''