Exemple #1
0
def create_library_block_child(parent_usage_key, block_type, definition_id):
    """
    Create a new XBlock definition in this library of the specified type (e.g.
    "html"), and add it as a child of the specified existing block.

    The 'definition_id' value (which should be a string like "problem1") will be
    used as both the definition_id and the usage_id of the child.
    """
    assert isinstance(parent_usage_key, LibraryUsageLocatorV2)
    # Load the parent block to make sure it exists and so we can modify its 'children' field:
    parent_block = load_block(parent_usage_key, user=None)
    if not parent_block.has_children:
        raise ValueError(
            "The specified parent XBlock does not allow child XBlocks.")
    # Create the new block in the library:
    metadata = create_library_block(parent_usage_key.context_key, block_type,
                                    definition_id)
    # Set the block as a child.
    # This will effectively "move" the newly created block from being a top-level block in the library to a child.
    include_data = XBlockInclude(link_id=None,
                                 block_type=block_type,
                                 definition_id=definition_id,
                                 usage_hint=None)
    parent_block.runtime.add_child_include(parent_block, include_data)
    parent_block.save()
    ref = ContentLibrary.objects.get_by_key(parent_usage_key.context_key)
    LIBRARY_BLOCK_UPDATED.send(sender=None,
                               library_key=ref.library_key,
                               usage_key=metadata.usage_key)
    return metadata
Exemple #2
0
def set_library_block_olx(usage_key, new_olx_str):
    """
    Replace the OLX source of the given XBlock.
    This is only meant for use by developers or API client applications, as
    very little validation is done and this can easily result in a broken XBlock
    that won't load.
    """
    # because this old pylint can't understand attr.ib() objects, pylint: disable=no-member
    assert isinstance(usage_key, LibraryUsageLocatorV2)
    # Make sure the block exists:
    metadata = get_library_block(usage_key)
    block_type = usage_key.block_type
    # Verify that the OLX parses, at least as generic XML:
    node = etree.fromstring(new_olx_str)
    if node.tag != block_type:
        raise ValueError(
            "Invalid root tag in OLX, expected {}".format(block_type))
    # Write the new XML/OLX file into the library bundle's draft
    draft = get_or_create_bundle_draft(metadata.def_key.bundle_uuid,
                                       DRAFT_NAME)
    write_draft_file(draft.uuid, metadata.def_key.olx_path,
                     new_olx_str.encode('utf-8'))
    # Clear the bundle cache so everyone sees the new block immediately:
    BundleCache(metadata.def_key.bundle_uuid, draft_name=DRAFT_NAME).clear()
    LIBRARY_BLOCK_UPDATED.send(sender=None,
                               library_key=usage_key.context_key,
                               usage_key=usage_key)
Exemple #3
0
def add_library_block_static_asset_file(usage_key, file_name, file_content):
    """
    Upload a static asset file into the library, to be associated with the
    specified XBlock. Will silently overwrite an existing file of the same name.

    file_name should be a name like "doc.pdf". It may optionally contain slashes
        like 'en/doc.pdf'
    file_content should be a binary string.

    Returns a LibraryXBlockStaticFile object.

    Example:
        video_block = UsageKey.from_string("lb:VideoTeam:python-intro:video:1")
        add_library_block_static_asset_file(video_block, "subtitles-en.srt", subtitles.encode('utf-8'))
    """
    assert isinstance(file_content, six.binary_type)
    def_key, lib_bundle = _lookup_usage_key(usage_key)
    if file_name != file_name.strip().strip('/'):
        raise InvalidNameError("file name cannot start/end with / or whitespace.")
    if '//' in file_name or '..' in file_name:
        raise InvalidNameError("Invalid sequence (// or ..) in filename.")
    file_path = lib_bundle.get_static_prefix_for_definition(def_key) + file_name
    # Write the new static file into the library bundle's draft
    draft = get_or_create_bundle_draft(def_key.bundle_uuid, DRAFT_NAME)
    write_draft_file(draft.uuid, file_path, file_content)
    # Clear the bundle cache so everyone sees the new file immediately:
    lib_bundle.cache.clear()
    file_metadata = blockstore_cache.get_bundle_file_metadata_with_cache(
        bundle_uuid=def_key.bundle_uuid, path=file_path, draft_name=DRAFT_NAME,
    )
    LIBRARY_BLOCK_UPDATED.send(sender=None, library_key=lib_bundle.library_key, usage_key=usage_key)
    return LibraryXBlockStaticFile(path=file_metadata.path, url=file_metadata.url, size=file_metadata.size)
Exemple #4
0
def delete_library_block_static_asset_file(usage_key, file_name):
    """
    Delete a static asset file from the library.

    Example:
        video_block = UsageKey.from_string("lb:VideoTeam:python-intro:video:1")
        delete_library_block_static_asset_file(video_block, "subtitles-en.srt")
    """
    def_key, lib_bundle = _lookup_usage_key(usage_key)
    if '..' in file_name:
        raise InvalidNameError("Invalid .. in file name.")
    file_path = lib_bundle.get_static_prefix_for_definition(def_key) + file_name
    # Delete the file from the library bundle's draft
    draft = get_or_create_bundle_draft(def_key.bundle_uuid, DRAFT_NAME)
    write_draft_file(draft.uuid, file_path, contents=None)
    # Clear the bundle cache so everyone sees the new file immediately:
    lib_bundle.cache.clear()
    LIBRARY_BLOCK_UPDATED.send(sender=None, library_key=lib_bundle.library_key, usage_key=usage_key)