Exemplo n.º 1
0
def delete_library_block(usage_key, remove_from_parent=True):
    """
    Delete the specified block from this library (and any children it has).

    If the block's definition (OLX file) is within this same library as the
    usage key, both the definition and the usage will be deleted.

    If the usage points to a definition in a linked bundle, the usage will be
    deleted but the link and the linked bundle will be unaffected.

    If the block is in use by some other bundle that links to this one, that
    will not prevent deletion of the definition.

    remove_from_parent: modify the parent to remove the reference to this
        delete block. This should always be true except when this function
        calls itself recursively.
    """
    assert isinstance(usage_key, LibraryUsageLocatorV2)
    library_context = get_learning_context_impl(usage_key)
    library_ref = ContentLibrary.objects.get_by_key(usage_key.context_key)
    def_key = library_context.definition_for_usage(usage_key)
    if def_key is None:
        raise ContentLibraryBlockNotFound(usage_key)
    lib_bundle = LibraryBundle(usage_key.context_key,
                               library_ref.bundle_uuid,
                               draft_name=DRAFT_NAME)
    # Create a draft:
    draft_uuid = get_or_create_bundle_draft(def_key.bundle_uuid,
                                            DRAFT_NAME).uuid
    # Does this block have a parent?
    if usage_key not in lib_bundle.get_top_level_usages(
    ) and remove_from_parent:
        # Yes: this is not a top-level block.
        # First need to modify the parent to remove this block as a child.
        raise NotImplementedError
    # Does this block have children?
    block = load_block(usage_key, user=None)
    if block.has_children:
        # Next, recursively call delete_library_block(...) on each child usage
        for child_usage in block.children:
            # Specify remove_from_parent=False to avoid unnecessary work to
            # modify this block's children list when deleting each child, since
            # we're going to delete this block anyways.
            delete_library_block(child_usage, remove_from_parent=False)
    # Delete the definition:
    if def_key.bundle_uuid == library_ref.bundle_uuid:
        # This definition is in the library, so delete it:
        path_prefix = lib_bundle.olx_prefix(def_key)
        for bundle_file in get_bundle_files(def_key.bundle_uuid,
                                            use_draft=DRAFT_NAME):
            if bundle_file.path.startswith(path_prefix):
                # Delete this file, within this definition's "folder"
                write_draft_file(draft_uuid, bundle_file.path, contents=None)
    else:
        # The definition must be in a linked bundle, so we don't want to delete
        # it; just the <xblock-include /> in the parent, which was already
        # deleted above.
        pass
    # Clear the bundle cache so everyone sees the deleted block immediately:
    lib_bundle.cache.clear()
Exemplo n.º 2
0
    def test_drafts_and_files(self):
        """
        Test creating, reading, writing, committing, and reverting drafts and
        files.
        """
        coll = api.create_collection("Test Collection")
        bundle = api.create_bundle(coll.uuid,
                                   title="Earth 🗿 Bundle",
                                   slug="earth",
                                   description="another test bundle")
        # Create a draft
        draft = api.get_or_create_bundle_draft(bundle.uuid,
                                               draft_name="test-draft")
        self.assertEqual(draft.bundle_uuid, bundle.uuid)
        self.assertEqual(draft.name, "test-draft")
        self.assertGreaterEqual(draft.updated_at.year, 2019)
        # And retrieve it again:
        draft2 = api.get_or_create_bundle_draft(bundle.uuid,
                                                draft_name="test-draft")
        self.assertEqual(draft, draft2)
        # Also test retrieving using get_draft
        draft3 = api.get_draft(draft.uuid)
        self.assertEqual(draft, draft3)

        # Write a file into the bundle:
        api.write_draft_file(draft.uuid, "test.txt", "initial version")
        # Now the file should be visible in the draft:
        draft_contents = api.get_bundle_file_data(bundle.uuid,
                                                  "test.txt",
                                                  use_draft=draft.name)
        self.assertEqual(draft_contents, "initial version")
        api.commit_draft(draft.uuid)

        # Write a new version into the draft:
        api.write_draft_file(draft.uuid, "test.txt", "modified version")
        published_contents = api.get_bundle_file_data(bundle.uuid, "test.txt")
        self.assertEqual(published_contents, "initial version")
        draft_contents2 = api.get_bundle_file_data(bundle.uuid,
                                                   "test.txt",
                                                   use_draft=draft.name)
        self.assertEqual(draft_contents2, "modified version")
        # Now delete the draft:
        api.delete_draft(draft.uuid)
        draft_contents3 = api.get_bundle_file_data(bundle.uuid,
                                                   "test.txt",
                                                   use_draft=draft.name)
        # Confirm the file is now reset:
        self.assertEqual(draft_contents3, "initial version")

        # Finaly, test the get_bundle_file* methods:
        file_info1 = api.get_bundle_file_metadata(bundle.uuid, "test.txt")
        self.assertEqual(file_info1.path, "test.txt")
        self.assertEqual(file_info1.size, len("initial version"))
        self.assertEqual(file_info1.hash_digest,
                         "a45a5c6716276a66c4005534a51453ab16ea63c4")

        self.assertEqual(api.get_bundle_files(bundle.uuid), [file_info1])
        self.assertEqual(api.get_bundle_files_dict(bundle.uuid), {
            "test.txt": file_info1,
        })
Exemplo n.º 3
0
    def test_drafts_and_files(self):
        """
        Test creating, reading, writing, committing, and reverting drafts and
        files.
        """
        coll = api.create_collection("Test Collection")
        bundle = api.create_bundle(coll.uuid,
                                   title="Earth 🗿 Bundle",
                                   slug="earth",
                                   description="another test bundle")
        # Create a draft
        draft = api.get_or_create_bundle_draft(bundle.uuid,
                                               draft_name="test-draft")
        assert draft.bundle_uuid == bundle.uuid
        assert draft.name == 'test-draft'
        assert draft.updated_at.year >= 2019
        # And retrieve it again:
        draft2 = api.get_or_create_bundle_draft(bundle.uuid,
                                                draft_name="test-draft")
        assert draft == draft2
        # Also test retrieving using get_draft
        draft3 = api.get_draft(draft.uuid)
        assert draft == draft3

        # Write a file into the bundle:
        api.write_draft_file(draft.uuid, "test.txt", b"initial version")
        # Now the file should be visible in the draft:
        draft_contents = api.get_bundle_file_data(bundle.uuid,
                                                  "test.txt",
                                                  use_draft=draft.name)
        assert draft_contents == b'initial version'
        api.commit_draft(draft.uuid)

        # Write a new version into the draft:
        api.write_draft_file(draft.uuid, "test.txt", b"modified version")
        published_contents = api.get_bundle_file_data(bundle.uuid, "test.txt")
        assert published_contents == b'initial version'
        draft_contents2 = api.get_bundle_file_data(bundle.uuid,
                                                   "test.txt",
                                                   use_draft=draft.name)
        assert draft_contents2 == b'modified version'
        # Now delete the draft:
        api.delete_draft(draft.uuid)
        draft_contents3 = api.get_bundle_file_data(bundle.uuid,
                                                   "test.txt",
                                                   use_draft=draft.name)
        # Confirm the file is now reset:
        assert draft_contents3 == b'initial version'

        # Finaly, test the get_bundle_file* methods:
        file_info1 = api.get_bundle_file_metadata(bundle.uuid, "test.txt")
        assert file_info1.path == 'test.txt'
        assert file_info1.size == len(b'initial version')
        assert file_info1.hash_digest == 'a45a5c6716276a66c4005534a51453ab16ea63c4'

        assert list(api.get_bundle_files(bundle.uuid)) == [file_info1]
        assert api.get_bundle_files_dict(bundle.uuid) == {
            'test.txt': file_info1
        }
Exemplo n.º 4
0
def get_bundle_draft_files_cached(bundle_uuid, draft_name):
    """
    Get the files in the specified bundle draft. Cached using BundleCache so we
    get automatic cache invalidation when the draft is updated.
    """
    bundle_cache = BundleCache(bundle_uuid, draft_name)
    cache_key = ('bundle_draft_files', )
    result = bundle_cache.get(cache_key)
    if result is None:
        result = list(blockstore_api.get_bundle_files(bundle_uuid, use_draft=draft_name))
        bundle_cache.set(cache_key, result)
    return result
Exemplo n.º 5
0
def get_bundle_draft_files_cached(bundle_uuid, draft_name):
    """
    Get the files in the specified bundle draft. Cached using BundleCache so we
    get automatic cache invalidation when the draft is updated.
    """
    bundle_cache = BundleCache(bundle_uuid, draft_name)

    # This key is `_v2` to avoid reading invalid values cached by a past version of this code with no timeout.
    cache_key = ('bundle_draft_files_v2', )
    result = bundle_cache.get(cache_key)
    if result is None:
        result = list(blockstore_api.get_bundle_files(bundle_uuid, use_draft=draft_name))
        bundle_cache.set(cache_key, result)
    return result