openedx.core.djangoapps.content_libraries.api package#
Submodules#
openedx.core.djangoapps.content_libraries.api.backup module#
Public API for content library backup (zip export) utilities.
- openedx.core.djangoapps.content_libraries.api.backup.create_library_v2_zip(library_key: LibraryLocatorV2, user) tuple#
Create a zip backup of a v2 library and return
(temp_dir, zip_file_path).The caller is responsible for cleaning up
temp_dirwhen done.- Parameters:
library_key – LibraryLocatorV2 identifying the library to export.
user – User object passed to the backup API.
- Returns:
A tuple of
(temp_dir as Path, zip_file_path as str).
- openedx.core.djangoapps.content_libraries.api.backup.extract_library_v2_zip_to_dir(library_key, root_dir, library_dir, username=None)#
Export a v2 library to a directory by creating a zip backup and extracting it.
V2 libraries are stored in Learning Core and use a zip-based backup mechanism. This function creates a temporary zip backup, extracts its contents into
library_dirunderroot_dir, then cleans up the temporary zip.- Parameters:
library_key – LibraryLocatorV2 for the library to export
root_dir – Root directory where library_dir will be created
library_dir – Directory name under root_dir to extract the library into
username – Username string for the backup API (optional)
- Raises:
Exception – If backup creation or extraction fails
DoesNotExist – If the specified user does not exist
openedx.core.djangoapps.content_libraries.api.block_metadata module#
Content libraries data classes related to XBlocks/Components.
- class openedx.core.djangoapps.content_libraries.api.block_metadata.LibraryHistoryContributor(username: str, profile_image_urls: ProfileImageUrls)#
Bases:
objectA contributor in a publish history group, with profile image URLs.
- classmethod from_user(user, request=None) LibraryHistoryContributor#
- profile_image_urls: ProfileImageUrls#
- username: str#
- class openedx.core.djangoapps.content_libraries.api.block_metadata.LibraryHistoryEntry(contributor: LibraryHistoryContributor | None, changed_at: datetime, title: str, item_type: str, action: str, old_version: int, new_version: int | None)#
Bases:
objectOne entry in the history of a library component.
- action: str#
- changed_at: datetime#
- contributor: LibraryHistoryContributor | None#
- item_type: str#
- new_version: int | None#
- old_version: int#
- title: str#
- class openedx.core.djangoapps.content_libraries.api.block_metadata.LibraryPublishHistoryGroup(publish_log_uuid: UUID, published_by: AbstractUser | None, published_at: datetime, contributors: list[LibraryHistoryContributor], direct_published_entities: list[DirectPublishedEntity], scope_entity_key: LibraryUsageLocatorV2 | LibraryContainerLocator | None)#
Bases:
objectSummary of a publish event for a library item.
Each instance represents one or more PublishLogRecords, and includes the set of contributors who authored draft changes between the previous publish and this one.
Pre-Verawood (direct=None): one group per entity × publish event. Post-Verawood (direct!=None): one group per unique PublishLog.
- contributors: list[LibraryHistoryContributor]#
- direct_published_entities: list[DirectPublishedEntity]#
- publish_log_uuid: UUID#
- published_at: datetime#
- published_by: AbstractUser | None#
- scope_entity_key: LibraryUsageLocatorV2 | LibraryContainerLocator | None#
- class openedx.core.djangoapps.content_libraries.api.block_metadata.LibraryXBlockMetadata(created: datetime, modified: datetime, display_name: str, tags_count: int = 0, *, draft_version_num: int, published_version_num: int | None = None, published_display_name: str | None, last_published: datetime | None = None, published_by: str | None = '', last_draft_created: datetime | None = None, last_draft_created_by: str = '', has_unpublished_changes: bool = False, collections: list[CollectionMetadata] = <factory>, can_stand_alone: bool = True, created_by: str | None = None, usage_key: LibraryUsageLocatorV2)#
Bases:
PublishableItemClass that represents the metadata about an XBlock in a content library.
- classmethod from_component(library_key, component, associated_collections=None)#
Construct a LibraryXBlockMetadata from a Component object.
- usage_key: LibraryUsageLocatorV2#
openedx.core.djangoapps.content_libraries.api.blocks module#
Content libraries API methods related to XBlocks/Components.
These methods don’t enforce permissions (only the REST APIs do).
- openedx.core.djangoapps.content_libraries.api.blocks.add_library_block_static_asset_file(usage_key: LibraryUsageLocatorV2, file_path: str, file_content: bytes, user: User | None = None) LibraryXBlockStaticFile#
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_path 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.
Sends a LIBRARY_BLOCK_UPDATED event.
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’))
- openedx.core.djangoapps.content_libraries.api.blocks.create_library_block(library_key: LibraryLocatorV2, block_type: str, definition_id: str, user_id: int | None = None, can_stand_alone: bool = True)#
Create a new XBlock in this library of the specified type (e.g. “html”).
Set can_stand_alone = False when a component is created under a container, like unit.
- openedx.core.djangoapps.content_libraries.api.blocks.delete_library_block(usage_key: LibraryUsageLocatorV2, user_id: int | None = None) None#
Delete the specified block from this library (soft delete).
- openedx.core.djangoapps.content_libraries.api.blocks.delete_library_block_static_asset_file(usage_key, file_path, user=None)#
Delete a static asset file from the library.
Sends a LIBRARY_BLOCK_UPDATED event.
Example
video_block = UsageKey.from_string(“lb:VideoTeam:python-intro:video:1”) delete_library_block_static_asset_file(video_block, “subtitles-en.srt”)
- openedx.core.djangoapps.content_libraries.api.blocks.get_component_from_usage_key(usage_key: UsageKeyV2) Component#
Fetch the Component object for a given usage key.
Raises a ObjectDoesNotExist error if no such Component exists.
This is a lower-level function that will return a Component even if there is no current draft version of that Component (because it’s been soft-deleted).
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_block(usage_key: LibraryUsageLocatorV2, include_collections=False) LibraryXBlockMetadata#
Get metadata about (the draft version of) one specific XBlock in a library.
This will raise ContentLibraryBlockNotFound if there is no draft version of this block (i.e. it’s been soft-deleted from Studio), even if there is a live published version of it in the LMS.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_block_static_asset_files(usage_key: LibraryUsageLocatorV2) list[LibraryXBlockStaticFile]#
Given an XBlock in a content library, list all the static asset files associated with that XBlock.
Returns a list of LibraryXBlockStaticFile objects, sorted by path.
TODO: Should this be in the general XBlock API rather than the libraries API?
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_collections(library_key: LibraryLocatorV2) QuerySet#
Get all collections in the given content library.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_component_creation_entry(usage_key: LibraryUsageLocatorV2, request=None) LibraryHistoryEntry | None#
Return the creation entry for a library component.
This is a single LibraryHistoryEntry representing the moment the component was first created. Returns None if the component has no versions yet.
Raises ContentLibraryBlockNotFound if the component does not exist.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_component_draft_history(usage_key: LibraryUsageLocatorV2, request=None) list[LibraryHistoryEntry]#
Return the draft change history for a library component since its last publication, ordered from most recent to oldest.
Raises ContentLibraryBlockNotFound if the component does not exist.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_component_publish_history(usage_key: LibraryUsageLocatorV2, request=None) list[LibraryPublishHistoryGroup]#
Return the publish history of a library component as a list of groups.
Each group corresponds to one publish event (PublishLogRecord) and includes: - who published and when - the distinct set of contributors: users who authored draft changes between
the previous publish and this one (via DraftChangeLogRecord version bounds)
direct_published_entities per era: - Pre-Verawood (direct=None): single entry for the component itself. - Post-Verawood, direct=True: single entry for the component (directly published). - Post-Verawood, direct=False: all direct=True records from the same PublishLog
(e.g. a parent container that was directly published).
Groups are ordered most-recent-first. Returns [] if the component has never been published.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_component_publish_history_entries(usage_key: LibraryUsageLocatorV2, publish_log_uuid: UUID, request=None) list[LibraryHistoryEntry]#
Return the individual draft change entries for a specific publish event.
Called lazily when the user expands a publish event in the UI. Entries are the DraftChangeLogRecords that fall between the previous publish event and this one, ordered most-recent-first.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_components(library_key: LibraryLocatorV2, text_search: str | None = None, block_types: list[str] | None = None) QuerySet#
Get the library components and filter.
TODO: Full text search needs to be implemented as a custom lookup for MySQL, but it should have a fallback to still work in SQLite.
- openedx.core.djangoapps.content_libraries.api.blocks.get_library_containers(library_key: LibraryLocatorV2) QuerySet#
Get all containers in the given content library.
- openedx.core.djangoapps.content_libraries.api.blocks.get_or_create_olx_media_type(block_type: str) MediaType#
Get or create a MediaType for the block type.
openedx_content stores all Content with a Media Type (a.k.a. MIME type). For OLX, we use the “application/vnd.*” convention, per RFC 6838.
- openedx.core.djangoapps.content_libraries.api.blocks.import_staged_content_from_user_clipboard(library_key: LibraryLocatorV2, user) PublishableItem#
Create a new library item from the staged content from clipboard. Can create containers (e.g. units) or XBlocks.
Returns the newly created item metadata
- openedx.core.djangoapps.content_libraries.api.blocks.publish_component_changes(usage_key: LibraryUsageLocatorV2, user_id: int)#
Publish all pending changes in a single component.
- openedx.core.djangoapps.content_libraries.api.blocks.restore_library_block(usage_key: LibraryUsageLocatorV2, user_id: int | None = None) None#
Restore the specified library block.
- openedx.core.djangoapps.content_libraries.api.blocks.set_library_block_olx(usage_key: LibraryUsageLocatorV2, new_olx_str: str, paths_to_media: dict | None = None, created_by: int | None = None) ComponentVersion#
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.
The optional
paths_to_mediaparameter can be used to attach openedx_content Media to this XBlock. A common use case for this would be to add images or other static assets to a text block:figure_a_media = content_api.get_or_create_file_media(...) paths_to_media={ 'static/figure_a.png': figure_a_media, }
Returns the version number of the newly created ComponentVersion.
- openedx.core.djangoapps.content_libraries.api.blocks.validate_can_add_block_to_library(library_key: LibraryLocatorV2, block_type: str, block_id: str) tuple[ContentLibrary, LibraryUsageLocatorV2]#
Perform checks to validate whether a new block with block_id and type block_type can be added to the library with key library_key.
Returns the ContentLibrary that has the passed in library_key and newly created LibraryUsageLocatorV2 if validation successful, otherwise raises errors.
openedx.core.djangoapps.content_libraries.api.collections module#
Python API for library collections#
- openedx.core.djangoapps.content_libraries.api.collections.create_library_collection(library_key: LibraryLocatorV2, collection_key: str, title: str, *, description: str = '', created_by: int | None = None, content_library: ContentLibrary | None = None) Collection#
Creates a Collection in the given ContentLibrary.
If you’ve already fetched a ContentLibrary for the given library_key, pass it in here to avoid refetching.
- openedx.core.djangoapps.content_libraries.api.collections.get_library_collection_from_locator(collection_locator: LibraryCollectionLocator) Collection#
Return a Collection using the LibraryCollectionLocator
- openedx.core.djangoapps.content_libraries.api.collections.library_collection_locator(library_key: LibraryLocatorV2, collection_key: str) LibraryCollectionLocator#
Returns the LibraryCollectionLocator associated to a collection
- openedx.core.djangoapps.content_libraries.api.collections.set_library_item_collections(library_key: LibraryLocatorV2, entity_ref: str, *, collection_keys: list[str], created_by: int | None = None, content_library: ContentLibrary | None = None) PublishableEntity#
It Associates the publishable_entity with collections for the given collection keys.
Only collections in queryset are associated with publishable_entity, all previous publishable_entity-collections associations are removed.
If you’ve already fetched the ContentLibrary, pass it in to avoid refetching.
Raises: * ContentLibraryCollectionNotFound if any of the given collection_keys don’t match Collections in the given library.
Returns the updated PublishableEntity.
- openedx.core.djangoapps.content_libraries.api.collections.update_library_collection(library_key: LibraryLocatorV2, collection_key: str, *, title: str | None = None, description: str | None = None, content_library: ContentLibrary | None = None) Collection#
Updates a Collection in the given ContentLibrary.
- openedx.core.djangoapps.content_libraries.api.collections.update_library_collection_items(library_key: LibraryLocatorV2, collection_key: str, *, opaque_keys: list[OpaqueKey], created_by: int | None = None, remove=False, content_library: ContentLibrary | None = None) Collection#
Associates the Collection with items (XBlocks, Containers) for the given OpaqueKeys.
By default the items are added to the Collection. If remove=True, the items are removed from the Collection.
If you’ve already fetched the ContentLibrary, pass it in to avoid refetching.
Raises: * ContentLibraryCollectionNotFound if no Collection with the given pk is found in the given library. * ContentLibraryBlockNotFound if any of the given opaque_keys don’t match Components in the given library. * ContentLibraryContainerNotFound if any of the given opaque_keys don’t match Containers in the given library.
Returns the updated Collection.
openedx.core.djangoapps.content_libraries.api.container_metadata module#
Content libraries data classes related to Containers.
- class openedx.core.djangoapps.content_libraries.api.container_metadata.ContainerMetadata(created: datetime, modified: datetime, display_name: str, tags_count: int = 0, *, draft_version_num: int, published_version_num: int | None = None, published_display_name: str | None, last_published: datetime | None = None, published_by: str | None = '', last_draft_created: datetime | None = None, last_draft_created_by: str = '', has_unpublished_changes: bool = False, collections: list[CollectionMetadata] = <factory>, can_stand_alone: bool = True, created_by: str | None = None, container_key: LibraryContainerLocator, container_type_code: str, container_id: Container.ID)#
Bases:
PublishableItemClass that represents the metadata about a Container (e.g. Unit) in a content library.
- container_id: ID#
- container_key: LibraryContainerLocator#
- container_type_code: str#
- classmethod from_container(library_key, container: Container, associated_collections=None)#
Construct a ContainerMetadata object from a Container object.
- openedx.core.djangoapps.content_libraries.api.container_metadata.container_subclass_for_olx_tag(olx_tag: str) type[Container]#
Given an OLX tag code (e.g. “vertical” for <vertical>), get the corresponding Container subclass, e.g. Unit.
This method is specific to content libraries.
- openedx.core.djangoapps.content_libraries.api.container_metadata.library_container_locator(library_key: LibraryLocatorV2, container: Container) LibraryContainerLocator#
Returns a LibraryContainerLocator for the given library + container.
openedx.core.djangoapps.content_libraries.api.containers module#
API for containers (Sections, Subsections, Units) in Content Libraries
- openedx.core.djangoapps.content_libraries.api.containers.copy_container(container_key: LibraryContainerLocator, user_id: int) UserClipboardData#
[ 🛑 UNSTABLE ] Copy a container (a Section, Subsection, or Unit) to the content staging.
- openedx.core.djangoapps.content_libraries.api.containers.create_container(library_key: LibraryLocatorV2, container_cls: type[Container], slug: str | None, title: str, user_id: int | None, created: datetime | None = None) ContainerMetadata#
[ 🛑 UNSTABLE ] Create a container (a Section, Subsection, or Unit) in the specified content library.
It will initially be empty.
- openedx.core.djangoapps.content_libraries.api.containers.delete_container(container_key: LibraryContainerLocator) None#
[ 🛑 UNSTABLE ] Delete a container (a Section, Subsection, or Unit) (soft delete).
No-op if container doesn’t exist or has already been soft-deleted.
- openedx.core.djangoapps.content_libraries.api.containers.get_container(container_key: LibraryContainerLocator, *, include_collections=False) ContainerMetadata#
[ 🛑 UNSTABLE ] Get a container (a Section, Subsection, or Unit).
- openedx.core.djangoapps.content_libraries.api.containers.get_container_children(container_key: LibraryContainerLocator, *, published=False) list[LibraryXBlockMetadata | ContainerMetadata]#
[ 🛑 UNSTABLE ] Get the entities contained in the given container (e.g. the components/xblocks in a unit, units in a subsection, subsections in a section)
- openedx.core.djangoapps.content_libraries.api.containers.get_container_children_count(container_key: LibraryContainerLocator, published=False) int#
[ 🛑 UNSTABLE ] Get the count of entities contained in the given container (e.g. the components/xblocks in a unit)
- openedx.core.djangoapps.content_libraries.api.containers.get_containers_contains_item(key: LibraryUsageLocatorV2 | LibraryContainerLocator) list[ContainerMetadata]#
[ 🛑 UNSTABLE ] Get containers that contains the item, that can be a component or another container.
- openedx.core.djangoapps.content_libraries.api.containers.get_library_container_creation_entry(container_key: LibraryContainerLocator, request=None) LibraryHistoryEntry | None#
[ 🛑 UNSTABLE ] Return the creation entry for a library container.
This is a single LibraryHistoryEntry representing the moment the container was first created. Returns None if the container has no versions yet.
- openedx.core.djangoapps.content_libraries.api.containers.get_library_container_draft_history(container_key: LibraryContainerLocator, request=None) list[LibraryHistoryEntry]#
[ 🛑 UNSTABLE ] Return the combined draft history for a container and all of its descendant components, sorted from most-recent to oldest.
Each entry describes a single change log record: who made the change, when, what the title was at that point.
- openedx.core.djangoapps.content_libraries.api.containers.get_library_container_publish_history(container_key: LibraryContainerLocator, request=None) list[LibraryPublishHistoryGroup]#
[ 🛑 UNSTABLE ] Return the publish history of a container as a list of groups.
Pre-Verawood records (direct=None): one group per entity × publish event (same PublishLog may produce multiple groups — one per entity in scope).
Post-Verawood records (direct!=None): one group per unique PublishLog that touched the container or any descendant. Contributors are accumulated across all entities in that PublishLog within scope. direct_published_entities lists the entities the user directly clicked “Publish” on.
Groups are ordered most-recent-first. Returns [] if nothing has been published.
- openedx.core.djangoapps.content_libraries.api.containers.get_library_container_publish_history_entries(scope_entity_key: LibraryContainerLocator, publish_log_uuid: UUID, request=None) list[LibraryHistoryEntry]#
[ 🛑 UNSTABLE ] Return the individual draft change entries for all entities in scope that participated in a specific publish event.
scope_entity_key identifies the container being viewed — it defines which entities’ entries to return (the container + its descendants). This may differ from the direct_published_entities in the publish group (e.g. a parent Section was directly published, but the scope here is a child Unit).
Post-Verawood (direct!=None): returns entries for all entities in scope that participated in the PublishLog.
Pre-Verawood (direct=None): returns entries only for the container itself (old behavior — one group per entity, scope == directly published entity).
Returns [] if no entities in scope participated in this publish event.
- openedx.core.djangoapps.content_libraries.api.containers.get_library_object_hierarchy(object_key: LibraryUsageLocatorV2 | LibraryContainerLocator) ContainerHierarchy#
[ 🛑 UNSTABLE ] Returns the full ancestry and descendents of the library object with the given object_key.
TODO: We intend to replace this implementation with a more efficient one that makes fewer database queries in the future. More details being discussed in openedx/edx-platform#36813
- openedx.core.djangoapps.content_libraries.api.containers.library_container_locator(library_key: LibraryLocatorV2, container: Container) LibraryContainerLocator#
Returns a LibraryContainerLocator for the given library + container.
- openedx.core.djangoapps.content_libraries.api.containers.publish_container_changes(container_key: LibraryContainerLocator, user_id: int | None) None#
[ 🛑 UNSTABLE ] Publish all unpublished changes in a container and all its child containers/blocks.
- openedx.core.djangoapps.content_libraries.api.containers.restore_container(container_key: LibraryContainerLocator) None#
[ 🛑 UNSTABLE ] Restore the specified library container.
- openedx.core.djangoapps.content_libraries.api.containers.update_container(container_key: LibraryContainerLocator, display_name: str, user_id: int | None) ContainerMetadata#
[ 🛑 UNSTABLE ] Update a container (a Section, Subsection, or Unit) title.
- openedx.core.djangoapps.content_libraries.api.containers.update_container_children(container_key: LibraryContainerLocator, children_keys: list[LibraryUsageLocatorV2] | list[LibraryContainerLocator], user_id: int | None, entities_action: ChildrenEntitiesAction = ChildrenEntitiesAction.REPLACE)#
[ 🛑 UNSTABLE ] Adds children components or containers to given container.
openedx.core.djangoapps.content_libraries.api.exceptions module#
Exceptions that can be thrown by the Content Libraries API.
- exception openedx.core.djangoapps.content_libraries.api.exceptions.BlockLimitReachedError#
Bases:
ExceptionMaximum number of allowed XBlocks in the library reached
- exception openedx.core.djangoapps.content_libraries.api.exceptions.ContentLibraryBlockNotFound(usage_id)#
Bases:
XBlockNotFoundErrorXBlock not found in the content library
- openedx.core.djangoapps.content_libraries.api.exceptions.ContentLibraryCollectionNotFound#
alias of
DoesNotExist
- openedx.core.djangoapps.content_libraries.api.exceptions.ContentLibraryContainerNotFound#
alias of
DoesNotExist
- openedx.core.djangoapps.content_libraries.api.exceptions.ContentLibraryNotFound#
alias of
DoesNotExist
- exception openedx.core.djangoapps.content_libraries.api.exceptions.IncompatibleTypesError#
Bases:
ExceptionLibrary type constraint violated
- exception openedx.core.djangoapps.content_libraries.api.exceptions.InvalidNameError#
Bases:
ValueErrorThe specified name/identifier is not valid
- exception openedx.core.djangoapps.content_libraries.api.exceptions.LibraryAlreadyExists#
Bases:
KeyErrorA library with the specified slug already exists
- exception openedx.core.djangoapps.content_libraries.api.exceptions.LibraryBlockAlreadyExists#
Bases:
KeyErrorAn XBlock with that ID already exists in the library
- exception openedx.core.djangoapps.content_libraries.api.exceptions.LibraryCollectionAlreadyExists#
Bases:
IntegrityErrorA Collection with that key already exists in the library
- exception openedx.core.djangoapps.content_libraries.api.exceptions.LibraryPermissionIntegrityError#
Bases:
IntegrityErrorThrown when an operation would cause insane permissions.
openedx.core.djangoapps.content_libraries.api.libraries module#
Python API for content libraries#
Via views.py, most of these API methods are also exposed as a REST API.
The API methods in this file are focused on authoring and specific to content libraries; they wouldn’t necessarily apply or work in other learning contexts such as courses, blogs, “pathways,” etc.
** As this is an authoring-focused API, all API methods in this file deal with the DRAFT version of the content library.**
Some of these methods will work and may be used from the LMS if needed (mostly for test setup; other use is discouraged), but some of the implementation details rely on Studio so other methods will raise errors if called from the LMS. (The REST API is not available at all from the LMS.)
Any APIs that use/affect content libraries but are generic enough to work in
other learning contexts too are in the core XBlock python/REST API at
openedx.core.djangoapps.xblock.api/rest_api.
For example, to render a content library XBlock as HTML, one can use the generic:
render_block_view(block, view_name, user)
That is an API in openedx.core.djangoapps.xblock.api (use it from Studio for
the draft version, from the LMS for published version).
There are one or two methods in this file that have some overlap with the core
XBlock API; for example, this content library API provides a
get_library_block() which returns metadata about an XBlock; it’s in this API
because it also returns data about whether or not the XBlock has unpublished
edits, which is an authoring-only concern. Likewise, APIs for getting/setting
an individual XBlock’s OLX directly seem more appropriate for small, reusable
components in content libraries and may not be appropriate for other learning
contexts so they are implemented here in the library API only. In the future,
if we find a need for these in most other learning contexts then those methods
could be promoted to the core XBlock API and made generic.
- class openedx.core.djangoapps.content_libraries.api.libraries.AccessLevel#
Bases:
objectEnum defining library access levels/permissions
- ADMIN_LEVEL = 'admin'#
- AUTHOR_LEVEL = 'author'#
- NO_ACCESS = None#
- READ_LEVEL = 'read'#
- class openedx.core.djangoapps.content_libraries.api.libraries.CollectionMetadata(key: str, title: str)#
Bases:
objectClass to represent collection metadata in a content library.
- key: str#
- title: str#
- class openedx.core.djangoapps.content_libraries.api.libraries.ContentLibrary(*args, **kwargs)#
Bases:
ModelA Content Library is a collection of content (XBlocks and/or static assets)
All actual content is stored in openedx_content, and any data that we’d want to transfer to another instance if this library were exported and then re-imported on another Open edX instance should be kept in openedx_content. This model in Studio should only be used to track settings specific to this Open edX instance, like who has permission to edit this content library.
- exception DoesNotExist#
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned#
Bases:
MultipleObjectsReturned
- allow_public_learning#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- allow_public_read#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- authz_scopes#
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.childrenis aReverseManyToOneDescriptorinstance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()defined below.
- get_license_display(*, field=<django.db.models.fields.CharField: license>)#
- id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- learning_package#
Accessor to the related object on the forward side of a one-to-one relation.
In the example:
class Restaurant(Model): place = OneToOneField(Place, related_name='restaurant')
Restaurant.placeis aForwardOneToOneDescriptorinstance.
- learning_package_id#
- property library_key#
Get the LibraryLocatorV2 opaque key for this library
- license#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- objects: ClassVar[ContentLibraryManager] = <openedx.core.djangoapps.content_libraries.models.ContentLibraryManager object>#
- org#
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parentis aForwardManyToOneDescriptorinstance.
- org_id#
- permission_grants#
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.childrenis aReverseManyToOneDescriptorinstance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()defined below.
- slug#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- class openedx.core.djangoapps.content_libraries.api.libraries.ContentLibraryMetadata(key: LibraryLocatorV2, learning_package_id: ID | None, title: str = '', description: str = '', num_blocks: int = 0, version: int = 0, last_published: datetime | None = None, published_by: str = '', last_draft_created: datetime | None = None, last_draft_created_by: str = '', has_unpublished_changes: bool = False, has_unpublished_deletes: bool = False, allow_public_learning: bool = False, allow_public_read: bool = False, license: str = '', created: datetime | None = None, updated: datetime | None = None)#
Bases:
objectClass that represents the metadata about a content library.
- allow_public_learning: bool = False#
- allow_public_read: bool = False#
- created: datetime | None = None#
- description: str = ''#
- has_unpublished_changes: bool = False#
- has_unpublished_deletes: bool = False#
- key: LibraryLocatorV2#
- last_draft_created: datetime | None = None#
- last_draft_created_by: str = ''#
- last_published: datetime | None = None#
- learning_package_id: ID | None#
- license: str = ''#
- num_blocks: int = 0#
- published_by: str = ''#
- title: str = ''#
- updated: datetime | None = None#
- version: int = 0#
- class openedx.core.djangoapps.content_libraries.api.libraries.ContentLibraryPermissionEntry(user: AbstractUser | None = None, group: Group | None = None, access_level: str | None = None)#
Bases:
objectA user or group granted permission to use a content library.
- access_level: str | None = None#
- user: AbstractUser | None = None#
- class openedx.core.djangoapps.content_libraries.api.libraries.LibraryXBlockType(block_type: str, display_name: str)#
Bases:
objectAn XBlock type that can be added to a content library
- block_type: str#
- display_name: str#
- openedx.core.djangoapps.content_libraries.api.libraries.assign_library_role_to_user(library_key: LibraryLocatorV2, user: User, access_level: str)#
Grant a role to the specified user for this library.
- Parameters:
library_key (LibraryLocatorV2) – The key of the content library.
user (UserType) – The user to whom the role will be granted.
access_level (str | None) – The access level to be granted. This access level maps to a specific role.
- Raises:
TypeError – If the user is an instance of AnonymousUser.
- openedx.core.djangoapps.content_libraries.api.libraries.create_library(org: str, slug: str, title: str, description: str = '', allow_public_learning: bool = False, allow_public_read: bool = False, library_license: str = '', learning_package: LearningPackage | None = None) ContentLibraryMetadata#
Create a new content library.
org: an organizations.models.Organization instance
slug: a slug for this library like ‘physics-problems’
title: title for this library
description: description of this library
allow_public_learning: Allow anyone to read/learn from blocks in the LMS
allow_public_read: Allow anyone to view blocks (including source) in Studio?
learning_package: A learning package to associate with this library.
Returns a ContentLibraryMetadata instance.
- openedx.core.djangoapps.content_libraries.api.libraries.delete_library(library_key: LibraryLocatorV2) None#
Delete a content library
- openedx.core.djangoapps.content_libraries.api.libraries.get_allowed_block_types(library_key: LibraryLocatorV2)#
Get a list of XBlock types that can be added to the specified content library.
- openedx.core.djangoapps.content_libraries.api.libraries.get_backup_task_status(user_id: int, task_id: str) dict | None#
Get the status of a library backup task.
- Returns a dictionary with the following keys:
state: One of “Pending”, “Exporting”, “Succeeded”, “Failed”
file: If state is “Succeeded”, the FileField of the exported .zip. Otherwise, None.
If no task is found, returns None.
- openedx.core.djangoapps.content_libraries.api.libraries.get_libraries_for_user(user, org=None, text_search=None, order=None) QuerySet#
Return content libraries that the user has permission to view.
- openedx.core.djangoapps.content_libraries.api.libraries.get_library(library_key: LibraryLocatorV2) ContentLibraryMetadata#
Get the library with the specified key. Does not check permissions. returns a ContentLibraryMetadata instance.
Raises ContentLibraryNotFound if the library doesn’t exist.
- openedx.core.djangoapps.content_libraries.api.libraries.get_library_team(library_key: LibraryLocatorV2) list[ContentLibraryPermissionEntry]#
Get the list of users/groups granted permission to use this library.
- openedx.core.djangoapps.content_libraries.api.libraries.get_library_user_permissions(library_key: LibraryLocatorV2, user: User) ContentLibraryPermissionEntry | None#
Fetch the specified user’s access information. Will return None if no permissions have been granted.
- openedx.core.djangoapps.content_libraries.api.libraries.get_metadata(queryset: QuerySet, text_search: str | None = None) list[ContentLibraryMetadata]#
Take a list of ContentLibrary objects and return metadata from openedx_content.
- openedx.core.djangoapps.content_libraries.api.libraries.is_library_backup_task(task_name: str) bool#
Case-insensitive match to see if a task is a library backup.
- openedx.core.djangoapps.content_libraries.api.libraries.is_library_restore_task(task_name: str) bool#
Case-insensitive match to see if a task is a library restore.
- openedx.core.djangoapps.content_libraries.api.libraries.library_component_usage_key(library_key: LibraryLocatorV2, component: Component) LibraryUsageLocatorV2#
Returns a LibraryUsageLocatorV2 for the given library + component.
- openedx.core.djangoapps.content_libraries.api.libraries.publish_changes(library_key: LibraryLocatorV2, user_id: int | None = None)#
Publish all pending changes to the specified library.
- openedx.core.djangoapps.content_libraries.api.libraries.require_permission_for_library_key(library_key: LibraryLocatorV2, user: User, permission: str | PermissionData) ContentLibrary#
Check if the user has the specified permission for a content library.
- Parameters:
library_key – The library key identifying the content library
user – The user whose permissions are being checked
permission – Either a permission string from content_libraries.permissions or a PermissionData instance from the authz API
- Returns:
The library object if permission check passes
- Return type:
- Raises:
ContentLibraryNotFound – If the library with the given key doesn’t exist
PermissionDenied – If the user doesn’t have the required permission
- openedx.core.djangoapps.content_libraries.api.libraries.revert_changes(library_key: LibraryLocatorV2, user_id: int | None = None) None#
Revert all pending changes to the specified library, restoring it to the last published version.
- openedx.core.djangoapps.content_libraries.api.libraries.set_library_group_permissions(library_key: LibraryLocatorV2, group, access_level: str)#
Change the specified group’s level of access to this library.
access_level should be one of the AccessLevel values defined above.
- openedx.core.djangoapps.content_libraries.api.libraries.set_library_user_permissions(library_key: LibraryLocatorV2, user: User, access_level: str | None)#
Change the specified user’s level of access to this library.
access_level should be one of the AccessLevel values defined above.
- openedx.core.djangoapps.content_libraries.api.libraries.update_library(library_key: LibraryLocatorV2, title=None, description=None, allow_public_learning=None, allow_public_read=None, library_license=None)#
Update a library’s metadata (Slug cannot be changed as it would break IDs throughout the system.)
A value of None means “don’t change”.
- openedx.core.djangoapps.content_libraries.api.libraries.user_can_create_library(user: AbstractUser) bool#
Check if the user has permission to create a content library.
- openedx.core.djangoapps.content_libraries.api.libraries.user_has_permission_across_lib_authz_systems(user: User, permission: str | PermissionData, library_obj: ContentLibrary) bool#
Check whether a user has a given permission on a content library across both the legacy edx-platform permission system and the newer openedx-authz system.
The provided permission name is normalized to both systems (legacy and authz), and authorization is granted if either: - the user holds the legacy object-level permission on the ContentLibrary instance, or - the openedx-authz API allows the user for the corresponding permission on the library.
Note: Temporary: this function uses Bridgekeeper-based logic for cases not yet modeled in openedx-authz.
Current gaps covered here: - CAN_CREATE_CONTENT_LIBRARY: we call user.has_perm via Bridgekeeper to verify the user is a course creator. - CAN_VIEW_THIS_CONTENT_LIBRARY: we respect the allow_public_read flag via Bridgekeeper. - CAN_LEARN_FROM_THIS_CONTENT_LIBRARY: this permission doesn’t exist in the new authz system, but we are treating it as equivalent to view_library in the new system, so we check both the legacy permission and the authz permission. This means that if a user can view the library content, they can learn from it. If we want to remove the old check fully, we should either update the can_learn enforcement points or add that specific permission to the authz system.
Replace these with authz_api.is_user_allowed once openedx-authz supports these conditions natively (including global (*) roles).
- Parameters:
user – The Django user (or user-like object) to check.
permission – The permission identifier (either a legacy codename or an openedx-authz name).
library_obj – The ContentLibrary instance to check against.
- Returns:
True if the user is authorized by either system; otherwise False.
- Return type:
bool
openedx.core.djangoapps.content_libraries.api.permissions module#
Public permissions that are part of the content libraries API.
Deprecated. This module re-exports legacy content library permissions. See openedx/openedx-platform#37409.
openedx.core.djangoapps.content_libraries.api.serializers module#
Serializer classes for containers
- class openedx.core.djangoapps.content_libraries.api.serializers.ContainerSerializer(container_metadata: ContainerMetadata)#
Bases:
objectSerializes a container (a Section, Subsection, or Unit) to OLX.
- static_files: list[StaticFile]#
- tags: Dict[str, Dict[int, List[str]]]#
Module contents#
Python API for working with content libraries