class LibraryToolsServiceTest(MixedSplitTestCase):
    """
    Tests for library service.
    """
    shard = 1

    def setUp(self):
        super(LibraryToolsServiceTest, self).setUp()

        self.tools = LibraryToolsService(self.store)

    def test_list_available_libraries(self):
        """
        Test listing of libraries.
        """
        _ = LibraryFactory.create(modulestore=self.store)
        all_libraries = self.tools.list_available_libraries()
        self.assertTrue(all_libraries)
        self.assertEqual(len(all_libraries), 1)

    @patch('xmodule.modulestore.split_mongo.split.SplitMongoModuleStore.get_library_summaries')
    def test_list_available_libraries_fetch(self, mock_get_library_summaries):
        """
        Test that library list is compiled using light weight library summary objects.
        """
        _ = self.tools.list_available_libraries()
        self.assertTrue(mock_get_library_summaries.called)
Example #2
0
class LibraryToolsServiceTest(MixedSplitTestCase):
    """
    Tests for library service.
    """
    def setUp(self):
        super().setUp()
        self.tools = LibraryToolsService(self.store, self.user_id)

    def test_list_available_libraries(self):
        """
        Test listing of libraries.
        """
        _ = LibraryFactory.create(modulestore=self.store)
        all_libraries = self.tools.list_available_libraries()
        self.assertTrue(all_libraries)
        self.assertEqual(len(all_libraries), 1)

    @patch(
        'xmodule.modulestore.split_mongo.split.SplitMongoModuleStore.get_library_summaries'
    )
    def test_list_available_libraries_fetch(self, mock_get_library_summaries):
        """
        Test that library list is compiled using light weight library summary objects.
        """
        _ = self.tools.list_available_libraries()
        self.assertTrue(mock_get_library_summaries.called)
Example #3
0
class ContentLibraryToolsTest(MixedSplitTestCase, ContentLibrariesRestApiTest):
    """
    Tests for LibraryToolsService which interact with blockstore-based content libraries
    """
    def setUp(self):
        super().setUp()
        self.tools = LibraryToolsService(self.store, self.user.id)

    def test_import_from_blockstore(self):
        # Create a blockstore content library
        library = self._create_library(slug="testlib1_import", title="A Test Library", description="Testing XBlocks")
        # Create a unit block with an HTML block in it.
        unit_block_id = self._add_block_to_library(library["id"], "unit", "unit1")["id"]
        html_block_id = self._add_block_to_library(library["id"], "html", "html1", parent_block=unit_block_id)["id"]
        html_block = load_block(UsageKey.from_string(html_block_id), self.user)
        # Add assets and content to the HTML block
        self._set_library_block_asset(html_block_id, "test.txt", b"data", expect_response=200)
        self._set_library_block_olx(html_block_id, '<html><a href="/static/test.txt">Hello world</a></html>')

        # Create a modulestore course
        course = CourseFactory.create(modulestore=self.store, user_id=self.user.id)
        CourseInstructorRole(course.id).add_users(self.user)
        # Add Source from library block to the course
        sourced_block = self.make_block("library_sourced", course, user_id=self.user.id)

        # Import the unit block from the library to the course
        self.tools.import_from_blockstore(sourced_block, unit_block_id)

        # Verify imported block with its children
        self.assertEqual(len(sourced_block.children), 1)
        self.assertEqual(sourced_block.children[0].category, 'unit')

        imported_unit_block = self.store.get_item(sourced_block.children[0])
        self.assertEqual(len(imported_unit_block.children), 1)
        self.assertEqual(imported_unit_block.children[0].category, 'html')

        imported_html_block = self.store.get_item(imported_unit_block.children[0])
        self.assertIn('Hello world', imported_html_block.data)

        # Check that assets were imported and static paths were modified after importing
        assets = library_api.get_library_block_static_asset_files(html_block.scope_ids.usage_id)
        self.assertEqual(len(assets), 1)
        self.assertIn(assets[0].url, imported_html_block.data)

        # Check that reimporting updates the target block
        self._set_library_block_olx(html_block_id, '<html><a href="/static/test.txt">Foo bar</a></html>')
        self.tools.import_from_blockstore(sourced_block, unit_block_id)

        self.assertEqual(len(sourced_block.children), 1)
        imported_unit_block = self.store.get_item(sourced_block.children[0])
        self.assertEqual(len(imported_unit_block.children), 1)
        imported_html_block = self.store.get_item(imported_unit_block.children[0])
        self.assertNotIn('Hello world', imported_html_block.data)
        self.assertIn('Foo bar', imported_html_block.data)
Example #4
0
    def __init__(self, **kwargs):
        request_cache_dict = DEFAULT_REQUEST_CACHE.data
        store = modulestore()

        services = kwargs.setdefault('services', {})
        user = kwargs.get('user')
        if user and user.is_authenticated:
            services['completion'] = CompletionService(
                user=user, context_key=kwargs.get('course_id'))
        services['fs'] = xblock.reference.plugins.FSService()
        services['i18n'] = ModuleI18nService
        services['library_tools'] = LibraryToolsService(
            store, user_id=user.id if user else None)
        services['partitions'] = PartitionService(
            course_id=kwargs.get('course_id'), cache=request_cache_dict)
        services['settings'] = SettingsService()
        services['user_tags'] = UserTagsService(self)
        if badges_enabled():
            services['badging'] = BadgingService(
                course_id=kwargs.get('course_id'), modulestore=store)
        self.request_token = kwargs.pop('request_token', None)
        services['teams'] = TeamsService()
        services['teams_configuration'] = TeamsConfigurationService()
        services['call_to_action'] = CallToActionService()
        super(LmsModuleSystem, self).__init__(**kwargs)
Example #5
0
def _preview_module_system(request, descriptor, field_data):
    """
    Returns a ModuleSystem for the specified descriptor that is specialized for
    rendering module previews.

    request: The active django request
    descriptor: An XModuleDescriptor
    """

    course_id = descriptor.location.course_key
    display_name_only = (descriptor.category == 'static_tab')

    wrappers = [
        # This wrapper wraps the module in the template specified above
        partial(wrap_xblock,
                'PreviewRuntime',
                display_name_only=display_name_only,
                usage_id_serializer=unicode,
                request_token=request_token(request)),

        # This wrapper replaces urls in the output that start with /static
        # with the correct course-specific url for the static content
        partial(replace_static_urls, None, course_id=course_id),
        _studio_wrap_xblock,
    ]

    descriptor.runtime._services[
        'studio_user_permissions'] = StudioPermissionsService(request)  # pylint: disable=protected-access

    return PreviewModuleSystem(
        static_url=settings.STATIC_URL,
        # TODO (cpennington): Do we want to track how instructors are using the preview problems?
        track_function=lambda event_type, event: None,
        filestore=descriptor.runtime.resources_fs,
        get_module=partial(_load_preview_module, request),
        render_template=render_from_lms,
        debug=True,
        replace_urls=partial(static_replace.replace_static_urls,
                             data_directory=None,
                             course_id=course_id),
        user=request.user,
        can_execute_unsafe_code=(lambda: can_execute_unsafe_code(course_id)),
        get_python_lib_zip=(
            lambda: get_python_lib_zip(contentstore, course_id)),
        mixins=settings.XBLOCK_MIXINS,
        course_id=course_id,
        anonymous_student_id='student',

        # Set up functions to modify the fragment produced by student_view
        wrappers=wrappers,
        error_descriptor_class=ErrorDescriptor,
        get_user_role=lambda: get_user_role(request.user, course_id),
        descriptor_runtime=descriptor.runtime,
        services={
            "i18n": ModuleI18nService(),
            "field-data": field_data,
            "library_tools": LibraryToolsService(modulestore()),
            "user": DjangoXBlockUserService(request.user),
        },
    )
    def setUpClass(cls):

        super(LibraryTestCase, cls).setUpClass()

        cls.library = LibraryFactory.create(modulestore=cls.store)
        creator = UserFactory()

        cls.library_blocks = [
            ItemFactory.create(
                category="html",
                parent=cls.library,
                parent_location=cls.library.location,
                publish_item=False,
                user_id=creator.id,
                modulestore=cls.store,
            ) for _ in range(3)
        ]
        cls.libtools = LibraryToolsService(cls.store)
        cls.store.update_item(cls.library, creator.id)

        with cls.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, None):
            cls.course = CourseFactory.create(modulestore=cls.store)
            cls.course_key = cls.course.id

            with cls.store.bulk_operations(cls.course_key, emit_signals=False):
                cls.chapter = ItemFactory.create(
                    parent=cls.course,
                    parent_location=cls.course.location,
                    category="chapter",
                    modulestore=cls.store,
                    publish_item=False,
                )
                cls.sequential = ItemFactory.create(
                    parent=cls.chapter,
                    parent_location=cls.chapter.location,
                    category='sequential',
                    modulestore=cls.store,
                    publish_item=False,
                )
                cls.vertical = ItemFactory.create(
                    parent=cls.sequential,
                    parent_location=cls.sequential.location,
                    category='vertical',
                    modulestore=cls.store,
                    publish_item=False,
                )

                cls.lc_block = ItemFactory.create(
                    category="library_content",
                    parent=cls.vertical,
                    parent_location=cls.vertical.location,
                    max_count=2,
                    source_library_id=str(cls.library.location.library_key),
                    modulestore=cls.store,
                )
                # copy children from library to content block (LibaryContentDescriptor.tools.update_children?)
                cls.store.update_item(cls.course, creator.id)
                cls.store.update_item(cls.lc_block, creator.id)
Example #7
0
 def __init__(self, **kwargs):
     services = kwargs.setdefault('services', {})
     services['user_tags'] = UserTagsService(self)
     services['partitions'] = LmsPartitionService(
         user=kwargs.get('user'),
         course_id=kwargs.get('course_id'),
         track_function=kwargs.get('track_function', None),
     )
     services['library_tools'] = LibraryToolsService(modulestore())
     services['fs'] = xblock.reference.plugins.FSService()
     self.request_token = kwargs.pop('request_token', None)
     super(LmsModuleSystem, self).__init__(**kwargs)
Example #8
0
 def __init__(self, **kwargs):
     request_cache_dict = RequestCache.get_request_cache().data
     services = kwargs.setdefault('services', {})
     services['fs'] = xblock.reference.plugins.FSService()
     services['i18n'] = ModuleI18nService
     services['library_tools'] = LibraryToolsService(modulestore())
     services['partitions'] = PartitionService(
         course_id=kwargs.get('course_id'), cache=request_cache_dict)
     store = modulestore()
     services['settings'] = SettingsService()
     services['user_tags'] = UserTagsService(self)
     if badges_enabled():
         services['badging'] = BadgingService(
             course_id=kwargs.get('course_id'), modulestore=store)
     self.request_token = kwargs.pop('request_token', None)
     super(LmsModuleSystem, self).__init__(**kwargs)
Example #9
0
    def _bind_course_module(self, module):
        """
        Bind a module (part of self.course) so we can access student-specific data.
        """
        module_system = get_test_system(course_id=module.location.course_key)
        module_system.descriptor_runtime = module.runtime._descriptor_system  # pylint: disable=protected-access
        module_system._services['library_tools'] = LibraryToolsService(self.store)  # pylint: disable=protected-access

        def get_module(descriptor):
            """Mocks module_system get_module function"""
            sub_module_system = get_test_system(course_id=module.location.course_key)
            sub_module_system.get_module = get_module
            sub_module_system.descriptor_runtime = descriptor._runtime  # pylint: disable=protected-access
            descriptor.bind_for_student(sub_module_system, self.user.id)
            return descriptor

        module_system.get_module = get_module
        module.xmodule_runtime = module_system
    def setUp(self):
        super().setUp()

        self.tools = LibraryToolsService(self.store, self.user_id)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html", self.library, data=f"Hello world from block {i}")
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block(
            "library_content",
            self.vertical,
            max_count=1,
            source_library_id=str(self.library.location.library_key)
        )
    def setUp(self):
        super(LibraryContentTest, self).setUp()

        self.tools = LibraryToolsService(self.store)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html", self.library, data="Hello world from block {}".format(i))
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block(
            "library_content",
            self.vertical,
            max_count=1,
            source_libraries=[LibraryVersionReference(self.library.location.library_key)]
        )
    def __init__(self, modulestore, course_entry, default_class, module_data,
                 lazy, **kwargs):
        """
        Computes the settings inheritance and sets up the cache.

        modulestore: the module store that can be used to retrieve additional
        modules

        course_entry: the originally fetched enveloped course_structure w/ branch and course id info.
        Callers to _load_item provide an override but that function ignores the provided structure and
        only looks at the branch and course id

        module_data: a dict mapping Location -> json that was cached from the
            underlying modulestore
        """
        # needed by capa_problem (as runtime.filestore via this.resources_fs)
        if course_entry.course_key.course:
            root = modulestore.fs_root / course_entry.course_key.org / course_entry.course_key.course / course_entry.course_key.run
        else:
            root = modulestore.fs_root / str(course_entry.structure['_id'])
        root.makedirs_p()  # create directory if it doesn't exist

        id_manager = SplitMongoIdManager(self)
        kwargs.setdefault('id_reader', id_manager)
        kwargs.setdefault('id_generator', id_manager)

        super(CachingDescriptorSystem,
              self).__init__(field_data=None,
                             load_item=self._load_item,
                             resources_fs=OSFS(root),
                             **kwargs)
        self.modulestore = modulestore
        self.course_entry = course_entry
        # set course_id attribute to avoid problems with subsystems that expect
        # it here. (grading, for example)
        self.course_id = course_entry.course_key
        self.lazy = lazy
        self.module_data = module_data
        self.default_class = default_class
        self.local_modules = {}
        self._services['library_tools'] = LibraryToolsService(modulestore,
                                                              user_id=None)
    def setUp(self):
        super(LibraryContentTest, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments

        self.tools = LibraryToolsService(self.store, self.user_id)
        self.library = LibraryFactory.create(modulestore=self.store)
        self.lib_blocks = [
            self.make_block("html",
                            self.library,
                            data="Hello world from block {}".format(i))
            for i in range(1, 5)
        ]
        self.course = CourseFactory.create(modulestore=self.store)
        self.chapter = self.make_block("chapter", self.course)
        self.sequential = self.make_block("sequential", self.chapter)
        self.vertical = self.make_block("vertical", self.sequential)
        self.lc_block = self.make_block("library_content",
                                        self.vertical,
                                        max_count=1,
                                        source_library_id=six.text_type(
                                            self.library.location.library_key))
Example #14
0
 def setUp(self):
     super().setUp()
     self.tools = LibraryToolsService(self.store, self.user.id)
Example #15
0
    def setUp(self):
        super(LibraryToolsServiceTest, self).setUp()

        self.tools = LibraryToolsService(self.store)
Example #16
0
    def setUp(self):
        super(LibraryToolsServiceTest, self).setUp()

        self.tools = LibraryToolsService(self.store)
Example #17
0
def _update_and_import_module(
        module, store, user_id,
        source_course_id, dest_course_id,
        do_import_static=True, runtime=None):
    """
    Update all the module reference fields to the destination course id,
    then import the module into the destination course.
    """
    logging.debug(u'processing import of module %s...', unicode(module.location))

    def _update_module_references(module, source_course_id, dest_course_id):
        """
        Move the module to a new course.
        """
        def _convert_ref_fields_to_new_namespace(reference):  # pylint: disable=invalid-name
            """
            Convert a reference to the new namespace, but only
            if the original namespace matched the original course.

            Otherwise, returns the input value.
            """
            assert isinstance(reference, UsageKey)
            if source_course_id == reference.course_key:
                return reference.map_into_course(dest_course_id)
            else:
                return reference

        fields = {}
        for field_name, field in module.fields.iteritems():
            if field.scope != Scope.parent and field.is_set_on(module):
                if isinstance(field, Reference):
                    value = field.read_from(module)
                    if value is None:
                        fields[field_name] = None
                    else:
                        fields[field_name] = _convert_ref_fields_to_new_namespace(field.read_from(module))
                elif isinstance(field, ReferenceList):
                    references = field.read_from(module)
                    fields[field_name] = [_convert_ref_fields_to_new_namespace(reference) for reference in references]
                elif isinstance(field, ReferenceValueDict):
                    reference_dict = field.read_from(module)
                    fields[field_name] = {
                        key: _convert_ref_fields_to_new_namespace(reference)
                        for key, reference
                        in reference_dict.iteritems()
                    }
                elif field_name == 'xml_attributes':
                    value = field.read_from(module)
                    # remove any export/import only xml_attributes
                    # which are used to wire together draft imports
                    if 'parent_url' in value:
                        del value['parent_url']
                    if 'parent_sequential_url' in value:
                        del value['parent_sequential_url']

                    if 'index_in_children_list' in value:
                        del value['index_in_children_list']
                    fields[field_name] = value
                else:
                    fields[field_name] = field.read_from(module)
        return fields

    if do_import_static and 'data' in module.fields and isinstance(module.fields['data'], xblock.fields.String):
        # we want to convert all 'non-portable' links in the module_data
        # (if it is a string) to portable strings (e.g. /static/)
        module.data = rewrite_nonportable_content_links(
            source_course_id,
            dest_course_id,
            module.data
        )

    fields = _update_module_references(module, source_course_id, dest_course_id)
    asides = module.get_asides() if isinstance(module, XModuleMixin) else None

    block = store.import_xblock(
        user_id, dest_course_id, module.location.category,
        module.location.block_id, fields, runtime, asides=asides
    )

    # TODO: Move this code once the following condition is met.
    # Get to the point where XML import is happening inside the
    # modulestore that is eventually going to store the data.
    # Ticket: https://openedx.atlassian.net/browse/PLAT-1046
    if block.location.category == 'library_content':
        # if library exists, update source_library_version and children
        # according to this existing library and library content block.
        if store.get_library(block.source_library_key):
            LibraryToolsService(store).update_children(
                block,
                user_id,
                version=block.source_library_version
            )

    return block