- Split Modulestore, which was modified to support content libraries. Instead of just storing "course" structures, Split Modulestore now has the concept of a "course-like" structure, which is either a course or a library.
- Courses and libraries are implemented similarly, each with a directed acyclic graph (DAG) of XBlocks, and a history of all changes made. The graph of blocks for both courses and libraries are stored in the "structures" MongoDB collection.
- Split's "active_versions" MongoDB collection stores a list of all course-like objects (courses and libraries). Each one has an ("org", "course", "run") triplet which is the unique ID of that course-like object. In that triplet, "org" is the organization that published the course-like object, and "course" is the field that stores the name ID value of the course-like object, which may be a library name; e.g. if the library's ID is "library-v1:UniversityX+LIB100", then "org" is "UniversityX" and "course" is "LIB100". Since libraries do not have the concept of "runs", the "run" value of a library is always set to "library." The other difference between courses and libraries in this collection is that courses have a "version" object that contains a "draft-branch" and/or "published-branch" entries (that point to the current version of the course DAG in the "structures" collection), whereas libraries only have a "library" entry (which points to the current version of the library DAG in the same "structures" collection).
Screenshot of an "active_versions" collection, showing MongoDB documents for both a library and a course:
- Any XBlock's Scope.content field values will be stored in split's "definitions" collection. A single definition document may be shared among any uses of that same XBlock in libraries and courses.
- Documents in the split modulestore are considered immutable; any changes to content in a course or library result in a new version of the definition and/or structure object being created, and the active_versions record is then updated to point to the new versions. (This is just a note - this aspect of the modulestore was not changed when content libraries were added.)
- The Library Root XBlock, a simple structural XBlock analogous to the "course" XBlock. This XBlock is the root of each content library. It is found in the platform code at common/lib/xmodule/xmodule/library_root_xblock.py. This block is just a container and does not have any user-visible functionality.
- "LibraryLocator" and "LibraryUsageLocator" opaque keys, which are identifiers used to uniquely identify libraries and the XBlocks that are contained within a content library. - https://github.com/edx/opaque-keys/pull/46
- Studio support for editing content libraries - https://github.com/edx/edx-platform/pull/6046
- Studio Import/Export code allows exporting and importing content libraries as XML - https://github.com/edx/edx-platform/pull/6846
- The Randomized Content Block, an XModule that is used to show content from a library to students. In the code, the block is called the Library Content Module because the original intention was for it to support two "modes": randomized content and manually selected content. Since the latter mode was never implemented, the module's display name was changed to "Randomized Content Block."
- LibraryToolsService, an XBlock runtime service that provides some functionality that the Randomized Content Block (LibraryContentModule) needs in order to function, such as:
- list_available_libraries(): used in the Randomized Content Block settings UI to allow the user to select which content library to draw content from.
- get_library_version(): given a library ID, returns the current version number of that library. Used to determine when new/updated content has been added to a library.
- update_children(): described below in "How Components Are Copied Into the Course"
- ContentLibraryTransformer, a block transformer which allows Library Content modules to work with the Course Blocks API.
How Components Are Copied Into the Course