I needed this change because I found a bug:
1. Create a block with children in a content library
2. Delete that content library
3. Create a new identical block with children in a new content library.
4. If the OLX is identical to the original block, this new block will not load in the LMS.
The reason for the bug is that the .children field contains usage keys (which encode the library, for example), but the values were being stored in BlockstoreFieldData which caches really aggressively and caches based on the hash of the OLX. Since the OLX is identical, it assumes the .children values should be identical as well.
The fix was to move children to a children-specific field data store, and only store the part of the child data that is encoded by the OLX (the <xblock-include> data) in BlockstoreFieldData. This is a better match for the way the caching works and cleaned up a hacky part of the runtime (at least it's slightly less hacky now).
Implementation details:
* Anonymous users are assigned a unique ID (like
`anon42c08f9996194e2a9339`) which gets stored in the django session.
`block.scope_ids.user_id` and `block.runtime.anonymous_student_id`
will both return this value.
* User state for anonymous users is stored in the django cache and
automatically expires as the cache gets pruned. Because user state is
stored, anonymous users can use interactive blocks like capa problems.
* There is no mechanism for upgrading to a registered account and
keeping user state since the user state store for anonymous users
(EphemeralKeyValueStore) is completely different than the one for
registered users (DjangoKeyValueStore/"CSM"), and has no "list all
keys" functionality.
* "User State Summary" field values are shared among [recently active]
anonymous users but are not shared with registered users.
* Anonymous users can only access the `public_view` of XBlocks, not the
regular `student_view`.
This PR introduces some backend python + REST APIs for storing static
asset files along with an XBlock in a content library. It also updates
the new runtime to be able to load such static asset files.
Example use cases:
* Store an image file with an HTML block and then use the image inline
in the HTML block.
* Store a PDF file with an HTML block and provide a link in the HTML for
the learner to download the PDF.
* Store .srt files or even video .mp4 files that belong to a video
XBlock.
Within the bundle, these static asset files are stored in a "static/"
subfolder of the folder that contains the OLX file. Extending an
existing LMS/Studio convention, a static asset file such as "image.png"
is referenced within the OLX as "/static/image.png" and the URL will be
rewritten by the runtime.
This commit introduces the changes needed for XBlocks in Blockstore to save
their user state into CSM. Before this commit, all student state for Blockstore
blocks was ephemeral (in-process dict store).
Notes:
* The main risk factor of this PR is that it adds non-course keys to the
course_id field in CSM. If any code (like analytics?) reads course keys
directly out of CSM and doesn't have graceful handling for key types it
doesn't recognize, it could cause an issue. With the included changes to
opaque-keys, calling CourseKey.from_string(...) on these values will raise
InvalidKeyError since they're not CourseKeys. (But calling
LearningContextKey.from_string(...) will work for both course and library
keys.)
* This commit introduces a slight regression for the Studio view of XBlocks in
Blockstore content libraries: their state is now lost from request to request.
I have a follow up PR to give them a proper studio-appropriate state store,
but I want to review it separately so it doesn't hold up this PR and we can
test this PR on its own.
https://github.com/edx/edx-platform/pull/20645
This introduces:
* A new XBlock runtime that can read and write XBlocks that are persisted using
Blockstore instead of Modulestore. The new runtime is currently isolated so
that it can be tested without risk to the current courseware/runtime.
* Content Libraries v2, which store XBlocks in Blockstore not modulestore
* An API Client for Blockstore
* "Learning Context" plugin API. A learning context is a more abstract concept
than a course; it's a collection of XBlocks that serves some learning purpose.