From 281a84b2d4beab96f7bc387880279ea0454d75c2 Mon Sep 17 00:00:00 2001 From: Josue Balandrano Coronel Date: Tue, 16 Apr 2019 15:34:25 -0500 Subject: [PATCH] Map selected block locations to the correct target course id when importing to avoid loosing selections when exporting and then importing course contents. --- eoc_journal/eoc_journal.py | 39 ++++++++++++++++++++++++++++++++++++++ requirements-test.txt | 1 + setup.py | 2 +- tests/unit/__init__.py | 0 tests/unit/test_import.py | 32 +++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/test_import.py diff --git a/eoc_journal/eoc_journal.py b/eoc_journal/eoc_journal.py index 8b2dbdb..08629f0 100644 --- a/eoc_journal/eoc_journal.py +++ b/eoc_journal/eoc_journal.py @@ -24,6 +24,7 @@ from xblock.fragment import Fragment from xblockutils.resources import ResourceLoader from xblockutils.studio_editable import StudioEditableXBlockMixin +from opaque_keys.edx.keys import UsageKey, CourseKey from .api_client import ApiClient from .completion_api import CompletionApiClient @@ -530,3 +531,41 @@ def _expand_static_url(self, url, absolute=False): url = self._make_url_absolute(url) return url + + @classmethod + def parse_xml(cls, node, runtime, keys, id_generator): + """ + Use `node` to construct a new block. + Arguments: + node (:class:`~xml.etree.ElementTree.Element`): The xml node to parse into an xblock. + runtime (:class:`.Runtime`): The runtime to use while parsing. + keys (:class:`.ScopeIds`): The keys identifying where this block + will store its data. + id_generator (:class:`.IdGenerator`): An object that will allow the + runtime to generate correct definition and usage ids for + children of this block. + + Notes: + This method is overwritten from :class:`~xblock.mixins.XmlSerizalizationMixin`. + https://github.com/edx/XBlock/blob/master/xblock/mixins.py + """ + block = super(EOCJournalXBlock, cls).parse_xml(node, runtime, keys, id_generator) + course_id = getattr(id_generator, 'target_course_id', '') + + if not course_id: + return block + + course_id = unicode(normalize_id(course_id)) + course_key = CourseKey.from_string(course_id) + + transformed_block_ids = [] + for selected in block.selected_pb_answer_blocks: + usage_key = UsageKey.from_string(selected) + if usage_key.course_key == course_key: + transformed_block_ids.append(selected) + else: + mapped = usage_key.map_into_course(course_key) + transformed_block_ids.append(unicode(mapped)) + + block.selected_pb_answer_blocks = transformed_block_ids + return block diff --git a/requirements-test.txt b/requirements-test.txt index 4c5b6bf..859582b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -24,3 +24,4 @@ six web-fragments webob XBlock +edx-opaque-keys==0.4.4 diff --git a/setup.py b/setup.py index 4a30229..b145986 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ def package_data(pkg, roots): setup( name='xblock-eoc-journal', - version='0.2', + version='0.3', description='End of Course Journal XBlock', packages=[ 'eoc_journal', diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/test_import.py b/tests/unit/test_import.py new file mode 100644 index 0000000..8801475 --- /dev/null +++ b/tests/unit/test_import.py @@ -0,0 +1,32 @@ +""" +Test EOC Journal Block import. +""" + +import unittest +from mock import Mock, patch +from django.test import TestCase +from eoc_journal.eoc_journal import EOCJournalXBlock + + +class TestEOCJournalImport(TestCase): + """ + Test End of Course Journal Import + """ + + @patch('eoc_journal.eoc_journal.XBlock.parse_xml', + return_value=Mock(autospec=EOCJournalXBlock) + ) + def test_parse_xml(self, mock_xblock_parse_xml): + mock_xblock_parse_xml().selected_pb_answer_blocks = [ + 'i4x://Org/Course/pb-answer/b86edf60454b47dbb8f2e1b4e2d48d6a', + 'i4x://Org/Course/pb-answer/6f070c350e39429cbccfd3185a33621c', + 'i4x://Org/Course/pb-answer/a0b04a13d3074229b6be33fbc31de233', + 'i4x://Org/Course/pb-answer/927c5b8cd051475e937b8c1091a9feaf', + ] + mock_node = Mock() + mock_runtime = Mock() + mock_keys = Mock() + mock_id_generator = Mock(target_course_id='Org/CourseToImport/2014') + block = EOCJournalXBlock.parse_xml(mock_node, mock_runtime, mock_keys, mock_id_generator) + for block_id in block.selected_pb_answer_blocks: + self.assertTrue(block_id.startswith('i4x://Org/CourseToImport'))