コード例 #1
0
    def test_xml_export_import_cycle(self):
        """
        Test the export-import cycle.
        """
        # Children will only set after calling this.
        self.lc_block.refresh_children()
        lc_block = self.store.get_item(self.lc_block.location)

        expected_olx = (
            '<library_content display_name="{block.display_name}" max_count="{block.max_count}"'
            ' source_library_id="{block.source_library_id}" source_library_version="{block.source_library_version}">\n'
            '  <html url_name="{block.children[0].block_id}"/>\n'
            '  <html url_name="{block.children[1].block_id}"/>\n'
            '  <html url_name="{block.children[2].block_id}"/>\n'
            '  <html url_name="{block.children[3].block_id}"/>\n'
            '</library_content>\n'
        ).format(
            block=lc_block,
        )

        export_fs = MemoryFS()
        # Set the virtual FS to export the olx to.
        lc_block.runtime._descriptor_system.export_fs = export_fs  # pylint: disable=protected-access

        # Export the olx.
        node = etree.Element("unknown_root")
        lc_block.add_xml_to_node(node)

        # Read it back
        with export_fs.open('{dir}/{file_name}.xml'.format(
            dir=lc_block.scope_ids.usage_id.block_type,
            file_name=lc_block.scope_ids.usage_id.block_id
        )) as f:
            exported_olx = f.read()

        # And compare.
        self.assertEqual(exported_olx, expected_olx)

        runtime = TestImportSystem(load_error_modules=True, course_id=lc_block.location.course_key)
        runtime.resources_fs = export_fs

        # Now import it.
        olx_element = etree.fromstring(exported_olx)
        id_generator = Mock()
        imported_lc_block = LibraryContentBlock.parse_xml(olx_element, runtime, None, id_generator)

        # Check the new XBlock has the same properties as the old one.
        self.assertEqual(imported_lc_block.display_name, lc_block.display_name)
        self.assertEqual(imported_lc_block.source_library_id, lc_block.source_library_id)
        self.assertEqual(imported_lc_block.source_library_version, lc_block.source_library_version)
        self.assertEqual(imported_lc_block.mode, lc_block.mode)
        self.assertEqual(imported_lc_block.max_count, lc_block.max_count)
        self.assertEqual(imported_lc_block.capa_type, lc_block.capa_type)
        self.assertEqual(len(imported_lc_block.children), 4)
        self.assertEqual(imported_lc_block.children, lc_block.children)
コード例 #2
0
    def _publish_events(self, block_structure, location, previous_count,
                        max_count, block_keys, user_id):
        """
        Helper method to publish events for analytics purposes
        """
        def format_block_keys(keys):
            """
            Helper function to format block keys
            """
            json_result = []
            for key in keys:
                info = block_structure.get_transformer_block_field(
                    key, ContentLibraryTransformer, 'block_analytics_summary')
                json_result.append(info)
            return json_result

        def publish_event(event_name, result, **kwargs):
            """
            Helper function to publish an event for analytics purposes
            """
            event_data = {
                "location": six.text_type(location),
                "previous_count": previous_count,
                "result": result,
                "max_count": max_count,
            }
            event_data.update(kwargs)
            context = contexts.course_context_from_course_id(
                location.course_key)
            if user_id:
                context['user_id'] = user_id
            full_event_name = "edx.librarycontentblock.content.{}".format(
                event_name)
            with tracker.get_tracker().context(full_event_name, context):
                tracker.emit(full_event_name, event_data)

        LibraryContentBlock.publish_selected_children_events(
            block_keys,
            format_block_keys,
            publish_event,
        )
コード例 #3
0
    def test_xml_export_import_cycle(self):
        """
        Test the export-import cycle.
        """
        # Read back the olx.
        with self.export_fs.open('{dir}/{file_name}.xml'.format(
            dir=self.lc_block.scope_ids.usage_id.block_type,
            file_name=self.lc_block.scope_ids.usage_id.block_id
        )) as f:
            exported_olx = f.read()

        # And compare.
        assert exported_olx == self.expected_olx

        # Now import it.
        olx_element = etree.fromstring(exported_olx)
        imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None, self.id_generator)

        self._verify_xblock_properties(imported_lc_block)
コード例 #4
0
    def test_xml_import_with_comments(self):
        """
        Test that XML comments within LibraryContentBlock are ignored during the import.
        """
        olx_with_comments = (
            '<!-- Comment -->\n'
            '<library_content display_name="{block.display_name}" max_count="{block.max_count}"'
            ' source_library_id="{block.source_library_id}" source_library_version="{block.source_library_version}">\n'
            '<!-- Comment -->\n'
            '  <html url_name="{block.children[0].block_id}"/>\n'
            '  <html url_name="{block.children[1].block_id}"/>\n'
            '  <html url_name="{block.children[2].block_id}"/>\n'
            '  <html url_name="{block.children[3].block_id}"/>\n'
            '</library_content>\n'
        ).format(
            block=self.lc_block,
        )

        # Import the olx.
        olx_element = etree.fromstring(olx_with_comments)
        imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None, self.id_generator)

        self._verify_xblock_properties(imported_lc_block)
コード例 #5
0
    def transform_block_filters(self, usage_info, block_structure):
        all_library_children = set()
        all_selected_children = set()
        for block_key in block_structure:
            if block_key.block_type != 'library_content':
                continue
            library_children = block_structure.get_children(block_key)
            if library_children:
                all_library_children.update(library_children)
                selected = []
                mode = block_structure.get_xblock_field(block_key, 'mode')
                max_count = block_structure.get_xblock_field(
                    block_key, 'max_count')

                # Retrieve "selected" json from LMS MySQL database.
                state_dict = get_student_module_as_dict(
                    usage_info.user, usage_info.course_key, block_key)
                for selected_block in state_dict.get('selected', []):
                    # Add all selected entries for this user for this
                    # library module to the selected list.
                    block_type, block_id = selected_block
                    usage_key = usage_info.course_key.make_usage_key(
                        block_type, block_id)
                    if usage_key in library_children:
                        selected.append(selected_block)

                # Update selected
                previous_count = len(selected)
                block_keys = LibraryContentBlock.make_selection(
                    selected, library_children, max_count, mode)
                selected = block_keys['selected']

                # Save back any changes
                if any(block_keys[changed]
                       for changed in ('invalid', 'overlimit', 'added')):
                    state_dict['selected'] = selected
                    StudentModule.save_state(
                        student=usage_info.user,
                        course_id=usage_info.course_key,
                        module_state_key=block_key,
                        defaults={
                            'state': json.dumps(state_dict),
                        },
                    )

                # publish events for analytics
                self._publish_events(
                    block_structure,
                    block_key,
                    previous_count,
                    max_count,
                    block_keys,
                    usage_info.user.id,
                )
                all_selected_children.update(
                    usage_info.course_key.make_usage_key(s[0], s[1])
                    for s in selected)

        def check_child_removal(block_key):
            """
            Return True if selected block should be removed.

            Block is removed if it is part of library_content, but has
            not been selected for current user.
            """
            if block_key not in all_library_children:
                return False
            if block_key in all_selected_children:
                return False
            return True

        return [block_structure.create_removal_filter(check_child_removal)]