Example #1
0
 def test_join_description_path(self):
     """Test for join_description_path"""
     self.assertEqual(api.join_description_paths(""), "")
     self.assertEqual(api.join_description_paths("", "foo"), "foo")
     self.assertEqual(api.join_description_paths("foo", ""), "foo")
     self.assertEqual(api.join_description_paths("foo", "", "bar"), "foo / bar")
     self.assertEqual(api.join_description_paths("foo", "bar", "b az"), "foo / bar / b az")
Example #2
0
 def test_join_description_path(self):
     """Test for join_description_path"""
     self.assertEqual(api.join_description_paths(''), '')
     self.assertEqual(api.join_description_paths('', 'foo'), 'foo')
     self.assertEqual(api.join_description_paths('foo', ''), 'foo')
     self.assertEqual(api.join_description_paths('foo', '', 'bar'),
                      'foo / bar')
     self.assertEqual(api.join_description_paths('foo', 'bar', 'b az'),
                      'foo / bar / b az')
Example #3
0
 def test_update_description_path(self):
     """Tests for update_description_path"""
     # after created a resource without parent has the description path
     # equal to the title
     self.assertIsNone(self.resource.parent)
     self.assertEqual(self.resource.title, self.resource.description_path)
     # changing the title does not update the description path automatically
     self.resource.title = "123 xyz"
     self.resource.save()
     self.assertNotEqual(self.resource.title, self.resource.description_path)
     # update the description path
     api.update_description_path(self.resource)
     self.assertEqual(self.resource.title, self.resource.description_path)
     # create a child resource
     child_res = self.create_resource(parent=self.resource)
     # the description path is the combination of the child resource title
     # and the parent description path
     self.assertEqual(
         child_res.description_path, api.join_description_paths(self.resource.description_path, child_res.title)
     )
     # change both resources title
     self.resource.title = "1234 xyza"
     self.resource.save()
     child_res.title = "foo 1234"
     child_res.save()
     # note: child_res.parent and self.resource are 2 different instances
     # of the same record, but they need to be refreshed separately
     # after a change made to one of them
     child_res.parent.refresh_from_db()
     # update the description path of the child
     # will not update the parent's one
     api.update_description_path(child_res)
     self.assertNotEqual(self.resource.title, self.resource.description_path)
     self.assertEqual(
         child_res.description_path, api.join_description_paths(self.resource.description_path, child_res.title)
     )
     # but the parent's update can be forced
     api.update_description_path(child_res, force_parent_update=True)
     self.resource.refresh_from_db()
     self.assertEqual(self.resource.title, self.resource.description_path)
     self.assertEqual(
         child_res.description_path, api.join_description_paths(self.resource.description_path, child_res.title)
     )
     # removing the description path of the parent
     self.resource.description_path = ""
     self.resource.title = "999 new title"
     self.resource.save()
     child_res.parent.refresh_from_db()
     # the update of the child will update the parent without forcing it
     api.update_description_path(child_res)
     self.resource.refresh_from_db()
     self.assertEqual(self.resource.title, self.resource.description_path)
Example #4
0
 def test_join_description_path(self):
     """Test for join_description_path"""
     self.assertEqual(
         api.join_description_paths(''),
         ''
     )
     self.assertEqual(
         api.join_description_paths('', 'foo'),
         'foo'
     )
     self.assertEqual(
         api.join_description_paths('foo', ''),
         'foo'
     )
     self.assertEqual(
         api.join_description_paths('foo', '', 'bar'),
         'foo / bar'
     )
     self.assertEqual(
         api.join_description_paths('foo', 'bar', 'b az'),
         'foo / bar / b az'
     )
Example #5
0
def import_children(course, element, parent, parent_dpath):
    """
    Create LearningResource instances for each element
    of an XML tree.

    Args:
        course (learningresources.models.Course): Course
        element (lxml.etree): XML element within xbundle
        parent (learningresources.models.LearningResource):
            Parent LearningResource
        parent_dpath (unicode): parent description path
    Returns:
        None
    """
    # pylint: disable=too-many-locals
    title = element.attrib.get("display_name", "MISSING")
    mpath = etree.ElementTree(element).getpath(element)
    dpath = join_description_paths(parent_dpath, title)
    resource = create_resource(
        course=course, parent=parent, resource_type=element.tag,
        title=title,
        content_xml=etree.tostring(element),
        mpath=mpath,
        url_name=element.attrib.get("url_name", None),
        dpath=dpath,
    )
    target = "/static/"
    if element.tag == "video":
        subname = get_video_sub(element)
        if subname != "":
            assets = StaticAsset.objects.filter(
                course__id=resource.course_id,
                asset=course_asset_basepath(course, subname),
            )
            for asset in assets:
                resource.static_assets.add(asset)
    else:
        # Recursively find all sub-elements, looking for anything which
        # refers to /static/. Then make the association between the
        # LearningResource and StaticAsset if the StaticAsset exists.
        # This is like doing soup.findAll("a") and checking for whether
        # "/static/" is in the href, which would work but also requires
        # more code to check for link, img, iframe, script, and others,
        # and within those, check for href or src existing.
        soup = BeautifulSoup(etree.tostring(element), 'lxml')
        for child in soup.findAll():
            for _, val in child.attrs.items():
                try:
                    if val.startswith(target):
                        path = val[len(target):]
                        try:
                            asset = StaticAsset.objects.get(
                                course__id=resource.course_id,
                                asset=course_asset_basepath(course, path),
                            )
                            resource.static_assets.add(asset)
                        except StaticAsset.DoesNotExist:
                            continue
                except AttributeError:
                    continue  # not a string

    for child in element.getchildren():
        if child.tag in DESCRIPTOR_TAGS:
            import_children(course, child, resource, dpath)
Example #6
0
 def test_update_description_path(self):
     """Tests for update_description_path"""
     # after created a resource without parent has the description path
     # equal to the title
     self.assertIsNone(self.resource.parent)
     self.assertEqual(
         self.resource.title,
         self.resource.description_path
     )
     # changing the title does not update the description path automatically
     self.resource.title = '123 xyz'
     self.resource.save()
     self.assertNotEqual(
         self.resource.title,
         self.resource.description_path
     )
     # update the description path
     api.update_description_path(self.resource)
     self.assertEqual(
         self.resource.title,
         self.resource.description_path
     )
     # create a child resource
     child_res = self.create_resource(
         parent=self.resource
     )
     # the description path is the combination of the child resource title
     # and the parent description path
     self.assertEqual(
         child_res.description_path,
         api.join_description_paths(
             self.resource.description_path,
             child_res.title
         )
     )
     # change both resources title
     self.resource.title = '1234 xyza'
     self.resource.save()
     child_res.title = 'foo 1234'
     child_res.save()
     # note: child_res.parent and self.resource are 2 different instances
     # of the same record, but they need to be refreshed separately
     # after a change made to one of them
     child_res.parent.refresh_from_db()
     # update the description path of the child
     # will not update the parent's one
     api.update_description_path(child_res)
     self.assertNotEqual(
         self.resource.title,
         self.resource.description_path
     )
     self.assertEqual(
         child_res.description_path,
         api.join_description_paths(
             self.resource.description_path,
             child_res.title
         )
     )
     # but the parent's update can be forced
     api.update_description_path(child_res, force_parent_update=True)
     self.resource.refresh_from_db()
     self.assertEqual(
         self.resource.title,
         self.resource.description_path
     )
     self.assertEqual(
         child_res.description_path,
         api.join_description_paths(
             self.resource.description_path,
             child_res.title
         )
     )
     # removing the description path of the parent
     self.resource.description_path = ''
     self.resource.title = '999 new title'
     self.resource.save()
     child_res.parent.refresh_from_db()
     # the update of the child will update the parent without forcing it
     api.update_description_path(child_res)
     self.resource.refresh_from_db()
     self.assertEqual(
         self.resource.title,
         self.resource.description_path
     )
     # update the title of the child to the "missing title" string
     self.resource.title = api.MissingTitle.for_title_field
     self.resource.save()
     api.update_description_path(self.resource)
     self.assertEqual(
         self.resource.title,
         api.MissingTitle.for_title_field
     )
     self.assertEqual(
         self.resource.description_path,
         api.MissingTitle.for_desc_path_field
     )
     # update also the child
     child_res.parent.refresh_from_db()
     api.update_description_path(child_res)
     self.assertEqual(
         child_res.description_path,
         api.join_description_paths(
             api.MissingTitle.for_desc_path_field,
             child_res.title
         )
     )
Example #7
0
def import_children(course, element, parent, parent_dpath):
    """
    Create LearningResource instances for each element
    of an XML tree.

    Args:
        course (learningresources.models.Course): Course
        element (lxml.etree): XML element within xbundle
        parent (learningresources.models.LearningResource):
            Parent LearningResource
        parent_dpath (unicode): parent description path
    Returns:
        None
    """
    # pylint: disable=too-many-locals
    title = element.attrib.get("display_name", MissingTitle.for_title_field)
    desc_path = title
    if desc_path == MissingTitle.for_title_field:
        desc_path = MissingTitle.for_desc_path_field
    mpath = etree.ElementTree(element).getpath(element)
    dpath = join_description_paths(parent_dpath, desc_path)
    resource = create_resource(
        course=course,
        parent=parent,
        resource_type=element.tag,
        title=title,
        content_xml=etree.tostring(element),
        mpath=mpath,
        url_name=element.attrib.get("url_name", None),
        dpath=dpath,
    )
    # temp variable to store static assets for bulk insert
    static_assets_to_save = set()
    target = "/static/"
    if element.tag == "video":
        subname = get_video_sub(element)
        if subname != "":
            assets = StaticAsset.objects.filter(
                course__id=resource.course_id,
                asset=course_asset_basepath(course, subname),
            )
            for asset in assets:
                static_assets_to_save.add((resource, asset))
    else:
        # Recursively find all sub-elements, looking for anything which
        # refers to /static/. Then make the association between the
        # LearningResource and StaticAsset if the StaticAsset exists.
        # This is like doing soup.findAll("a") and checking for whether
        # "/static/" is in the href, which would work but also requires
        # more code to check for link, img, iframe, script, and others,
        # and within those, check for href or src existing.
        soup = BeautifulSoup(etree.tostring(element), 'lxml')
        for child in soup.findAll():
            for _, val in child.attrs.items():
                try:
                    if val.startswith(target):
                        path = val[len(target):]
                        try:
                            asset = StaticAsset.objects.get(
                                course__id=resource.course_id,
                                asset=course_asset_basepath(course, path),
                            )
                            static_assets_to_save.add((resource, asset))
                        except StaticAsset.DoesNotExist:
                            continue
                except AttributeError:
                    continue  # not a string
    # Bulk insert of static assets
    # Using this approach to avoid signals during the learning resource .save()
    # Each signal triggers a reindex of the learning resource that is useless
    # during import because all the learning resources are indexed in bulk at
    # the end of the import anyway
    ThroughModel = LearningResource.static_assets.through
    ThroughModel.objects.bulk_create([
        ThroughModel(learningresource_id=resource.id, staticasset_id=asset.id)
        for resource, asset in static_assets_to_save
    ])

    for child in element.getchildren():
        if child.tag in DESCRIPTOR_TAGS:
            import_children(course, child, resource, dpath)
Example #8
0
def import_children(course, element, parent, parent_dpath):
    """
    Create LearningResource instances for each element
    of an XML tree.

    Args:
        course (learningresources.models.Course): Course
        element (lxml.etree): XML element within xbundle
        parent (learningresources.models.LearningResource):
            Parent LearningResource
        parent_dpath (unicode): parent description path
    Returns:
        None
    """
    # pylint: disable=too-many-locals
    title = element.attrib.get(
        "display_name", MissingTitle.for_title_field)
    desc_path = title
    if desc_path == MissingTitle.for_title_field:
        desc_path = MissingTitle.for_desc_path_field
    mpath = etree.ElementTree(element).getpath(element)
    dpath = join_description_paths(parent_dpath, desc_path)
    resource = create_resource(
        course=course, parent=parent, resource_type=element.tag,
        title=title,
        content_xml=etree.tostring(element),
        mpath=mpath,
        url_name=element.attrib.get("url_name", None),
        dpath=dpath,
    )
    # temp variable to store static assets for bulk insert
    static_assets_to_save = set()
    target = "/static/"
    if element.tag == "video":
        subname = get_video_sub(element)
        if subname != "":
            assets = StaticAsset.objects.filter(
                course__id=resource.course_id,
                asset=course_asset_basepath(course, subname),
            )
            for asset in assets:
                static_assets_to_save.add((resource, asset))
    else:
        # Recursively find all sub-elements, looking for anything which
        # refers to /static/. Then make the association between the
        # LearningResource and StaticAsset if the StaticAsset exists.
        # This is like doing soup.findAll("a") and checking for whether
        # "/static/" is in the href, which would work but also requires
        # more code to check for link, img, iframe, script, and others,
        # and within those, check for href or src existing.
        soup = BeautifulSoup(etree.tostring(element), 'lxml')
        for child in soup.findAll():
            for _, val in child.attrs.items():
                try:
                    if val.startswith(target):
                        path = val[len(target):]
                        try:
                            asset = StaticAsset.objects.get(
                                course__id=resource.course_id,
                                asset=course_asset_basepath(course, path),
                            )
                            static_assets_to_save.add((resource, asset))
                        except StaticAsset.DoesNotExist:
                            continue
                except AttributeError:
                    continue  # not a string
    # Bulk insert of static assets
    # Using this approach to avoid signals during the learning resource .save()
    # Each signal triggers a reindex of the learning resource that is useless
    # during import because all the learning resources are indexed in bulk at
    # the end of the import anyway
    ThroughModel = LearningResource.static_assets.through
    ThroughModel.objects.bulk_create(
        [
            ThroughModel(
                learningresource_id=resource.id,
                staticasset_id=asset.id
            )
            for resource, asset in static_assets_to_save
        ]
    )

    for child in element.getchildren():
        if child.tag in DESCRIPTOR_TAGS:
            import_children(course, child, resource, dpath)