openedx.core.djangoapps.content_libraries package#
Subpackages#
- openedx.core.djangoapps.content_libraries.api package
- Submodules
- openedx.core.djangoapps.content_libraries.api.block_metadata module
- openedx.core.djangoapps.content_libraries.api.blocks module
add_library_block_static_asset_file()create_library_block()delete_library_block()delete_library_block_static_asset_file()get_component_from_usage_key()get_library_block()get_library_block_static_asset_files()get_library_collections()get_library_components()get_library_containers()get_or_create_olx_media_type()import_staged_content_from_user_clipboard()publish_component_changes()restore_library_block()set_library_block_olx()validate_can_add_block_to_library()
- openedx.core.djangoapps.content_libraries.api.collections module
- openedx.core.djangoapps.content_libraries.api.container_metadata module
- openedx.core.djangoapps.content_libraries.api.containers module
copy_container()create_container()delete_container()get_container()get_container_children()get_container_children_count()get_containers_contains_item()get_library_object_hierarchy()library_container_locator()publish_container_changes()restore_container()update_container()update_container_children()
- openedx.core.djangoapps.content_libraries.api.courseware_import module
- openedx.core.djangoapps.content_libraries.api.exceptions module
- openedx.core.djangoapps.content_libraries.api.libraries module
- Python API for content libraries
AccessLevelCollectionMetadataContentLibraryContentLibrary.DoesNotExistContentLibrary.MultipleObjectsReturnedContentLibrary.allow_ltiContentLibrary.allow_public_learningContentLibrary.allow_public_readContentLibrary.authorize_lti_launch()ContentLibrary.authorized_lti_configsContentLibrary.authz_scopesContentLibrary.get_license_display()ContentLibrary.idContentLibrary.import_tasksContentLibrary.learning_packageContentLibrary.learning_package_idContentLibrary.library_keyContentLibrary.licenseContentLibrary.objectsContentLibrary.orgContentLibrary.org_idContentLibrary.permission_grantsContentLibrary.slug
ContentLibraryMetadataContentLibraryMetadata.allow_ltiContentLibraryMetadata.allow_public_learningContentLibraryMetadata.allow_public_readContentLibraryMetadata.createdContentLibraryMetadata.descriptionContentLibraryMetadata.has_unpublished_changesContentLibraryMetadata.has_unpublished_deletesContentLibraryMetadata.keyContentLibraryMetadata.last_draft_createdContentLibraryMetadata.last_draft_created_byContentLibraryMetadata.last_publishedContentLibraryMetadata.learning_package_idContentLibraryMetadata.licenseContentLibraryMetadata.num_blocksContentLibraryMetadata.published_byContentLibraryMetadata.titleContentLibraryMetadata.updatedContentLibraryMetadata.version
ContentLibraryPermissionEntryLibraryXBlockTypeassign_library_role_to_user()create_library()delete_library()get_allowed_block_types()get_backup_task_status()get_libraries_for_user()get_library()get_library_team()get_library_user_permissions()get_metadata()is_library_backup_task()is_library_restore_task()library_component_usage_key()publish_changes()require_permission_for_library_key()revert_changes()set_library_group_permissions()set_library_user_permissions()update_library()user_can_create_library()user_has_permission_across_lib_authz_systems()
- openedx.core.djangoapps.content_libraries.api.permissions module
- openedx.core.djangoapps.content_libraries.api.serializers module
- Module contents
- openedx.core.djangoapps.content_libraries.management package
- openedx.core.djangoapps.content_libraries.rest_api package
- Submodules
- openedx.core.djangoapps.content_libraries.rest_api.blocks module
- openedx.core.djangoapps.content_libraries.rest_api.collections module
LibraryCollectionsViewLibraryCollectionsView.create()LibraryCollectionsView.destroy()LibraryCollectionsView.get_content_library()LibraryCollectionsView.get_object()LibraryCollectionsView.get_queryset()LibraryCollectionsView.list()LibraryCollectionsView.lookup_fieldLibraryCollectionsView.partial_update()LibraryCollectionsView.restore()LibraryCollectionsView.retrieve()LibraryCollectionsView.serializer_classLibraryCollectionsView.update_items()
- openedx.core.djangoapps.content_libraries.rest_api.containers module
LibraryContainerChildrenViewLibraryContainerChildrenView.authentication_classesLibraryContainerChildrenView.delete()LibraryContainerChildrenView.dispatch()LibraryContainerChildrenView.get()LibraryContainerChildrenView.patch()LibraryContainerChildrenView.permission_classesLibraryContainerChildrenView.post()LibraryContainerChildrenView.serializer_class
LibraryContainerCollectionsViewLibraryContainerCopyViewLibraryContainerHierarchyLibraryContainerPublishViewLibraryContainerRestoreLibraryContainerViewLibraryContainersView
- openedx.core.djangoapps.content_libraries.rest_api.libraries module
- openedx.core.djangoapps.content_libraries.rest_api.serializers module
CollectionMetadataSerializerContainerHierarchyMemberSerializerContainerHierarchySerializerContentLibraryAddPermissionByEmailSerializerContentLibraryBlockImportTaskCreateSerializerContentLibraryBlockImportTaskSerializerContentLibraryCollectionSerializerContentLibraryCollectionUpdateSerializerContentLibraryFilterSerializerContentLibraryItemCollectionsUpdateSerializerContentLibraryItemContainerKeysSerializerContentLibraryItemKeysSerializerContentLibraryMetadataSerializerContentLibraryPermissionLevelSerializerContentLibraryPermissionSerializerContentLibraryUpdateSerializerLibraryBackupResponseSerializerLibraryBackupTaskStatusSerializerLibraryContainerMetadataSerializerLibraryContainerUpdateSerializerLibraryRestoreFileSerializerLibraryRestoreTaskRequestSerializerLibraryRestoreTaskResultSerializerLibraryXBlockCreationSerializerLibraryXBlockMetadataSerializerLibraryXBlockOlxSerializerLibraryXBlockStaticFileSerializerLibraryXBlockStaticFilesSerializerLibraryXBlockTypeSerializerOpaqueKeySerializerPublishableItemSerializerRestoreSuccessDataSerializerUnionLibraryMetadataSerializerUsageKeyV2Serializer
- openedx.core.djangoapps.content_libraries.rest_api.url_converters module
- openedx.core.djangoapps.content_libraries.rest_api.utils module
- Module contents
Submodules#
openedx.core.djangoapps.content_libraries.apps module#
Django AppConfig for Content Libraries Implementation
- class openedx.core.djangoapps.content_libraries.apps.ContentLibrariesConfig(app_name, app_module)#
Bases:
AppConfigDjango AppConfig for Content Libraries Implementation
- name = 'openedx.core.djangoapps.content_libraries'#
- plugin_app = {'settings_config': {'cms.djangoapp': {}}, 'url_config': {'cms.djangoapp': {'namespace': 'content_libraries'}}}#
- ready()#
Import signal handler’s module to ensure they are registered.
- verbose_name = 'Content Libraries (Learning-Core-based)'#
openedx.core.djangoapps.content_libraries.auth module#
Content Library LTI authentication.
This module offers an authentication backend to support LTI launches within content libraries.
- class openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend#
Bases:
ModelBackendAuthenticate based on content library LTI profile.
The backend assumes the profile was previously created and its presence is enough to assume the launch claims are valid.
- authenticate(request, iss=None, aud=None, sub=None, **kwargs)#
Authenticate if the user in the request has an LTI profile.
openedx.core.djangoapps.content_libraries.constants module#
Constants used for the content libraries.
openedx.core.djangoapps.content_libraries.library_context module#
Definition of “Library” as a learning context.
- class openedx.core.djangoapps.content_libraries.library_context.LibraryContextImpl(**kwargs)#
Bases:
LearningContextImplements content libraries as a learning context.
This is the new content libraries based on Learning Core, not the old content libraries based on modulestore.
- block_exists(usage_key: LibraryUsageLocatorV2)#
Does the block for this usage_key exist in this Library?
Note that this applies to all versions, i.e. you can put a usage key for a piece of content that has been soft-deleted (removed from Drafts), and it will still return True here. That’s because for the purposes of permission checking, we just want to know whether that block has ever existed in this Library, because we could be looking at any older version of it.
- can_edit_block(user: User | AnonymousUser, usage_key: UsageKeyV2) bool#
Assuming a block with the specified ID (usage_key) exists, does the specified user have permission to edit it (make changes to the fields / authored data store)?
May raise ContentLibraryNotFound if the library does not exist.
- can_view_block(user: User | AnonymousUser, usage_key: UsageKeyV2) bool#
Does the specified usage key exist in its context, and if so, does the specified user have permission to view it and interact with it (call handlers, save user state, etc.)?
May raise ContentLibraryNotFound if the library does not exist.
- can_view_block_for_editing(user: User | AnonymousUser, usage_key: UsageKeyV2) bool#
Assuming a block with the specified ID (usage_key) exists, does the specified user have permission to view its fields and OLX details (but not necessarily to make changes to it)?
May raise ContentLibraryNotFound if the library does not exist.
- send_block_updated_event(usage_key: UsageKeyV2)#
Send a “block updated” event for the library block with the given usage_key.
- send_container_updated_events(usage_key: UsageKeyV2)#
Send “container updated” events for containers that contains the library block with the given usage_key.
openedx.core.djangoapps.content_libraries.models module#
Content Libraries Models#
This module contains the models for new Content Libraries.
LTI 1.3 Models#
Content Libraries serves learning-core-based content through LTI 1.3 launches. The interface supports resource link launches and grading services. Two use cases justify the current data model to support LTI launches. They are:
Authentication and authorization. This use case demands management of user lifecycle to authorize access to content and grade submission, and it introduces a model to own the authentication business logic related to LTI.
Grade and assignments. When AGS is supported, content libraries store additional information concerning the launched resource so that, once the grading sub-system submits the score, it can retrieve them to propagate the score update into the LTI platform’s grade book.
Relationship with LMS’s lti_provider` models#
The data model above is similar to the one provided by the current LTI 1.1 implementation for modulestore and courseware content. But, Content Libraries is orthogonal. Its use-case is to offer standalone, embedded content from a specific backend (learning core). As such, it decouples from LTI 1.1. and the logic assume no relationship or impact across the two applications. The same reasoning applies to steps beyond the data model, such as at the XBlock runtime, authentication, and score handling, etc.
- class openedx.core.djangoapps.content_libraries.models.ContentLibrary(*args, **kwargs)#
Bases:
ModelA Content Library is a collection of content (XBlocks and/or static assets)
All actual content is stored in Learning Core, 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 Learning Core. 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
- property allow_lti#
True if there is at least one LTI tool configuration associated if this library.
- 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.
- classmethod authorize_lti_launch(library_key, *, issuer, client_id=None)#
Check if the given Issuer and Client ID are authorized to launch content from this library.
- authorized_lti_configs#
Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.
In the example:
class Pizza(Model): toppings = ManyToManyField(Topping, related_name='pizzas')
Pizza.toppingsandTopping.pizzasareManyToManyDescriptorinstances.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()defined below.
- 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.
- import_tasks#
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.
- 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.models.ContentLibraryBlockImportTask(*args, **kwargs)#
Bases:
ModelModel of a task to import blocks from an external source (e.g. modulestore).
- exception DoesNotExist#
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned#
Bases:
MultipleObjectsReturned
- TASK_CREATED = 'created'#
- TASK_FAILED = 'failed'#
- TASK_PENDING = 'pending'#
- TASK_RUNNING = 'running'#
- TASK_STATE_CHOICES = (('created', 'Task was created, but not queued to run.'), ('pending', 'Task was created and queued to run.'), ('running', 'Task is running.'), ('failed', 'Task finished, but some blocks failed to import.'), ('successful', 'Task finished successfully.'))#
- TASK_SUCCESSFUL = 'successful'#
- course_id#
DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!
A placeholder class that provides a way to set the attribute on the model.
- created_at#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- classmethod execute(import_task_id)#
A context manager to manage a task that is being executed.
- get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
- get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)#
- get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
- get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)#
- get_state_display(*, field=<django.db.models.fields.CharField: state>)#
- id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- library#
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.
- library_id#
- objects = <django.db.models.manager.Manager object>#
- progress#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- save_progress(progress)#
- state#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- updated_at#
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.models.ContentLibraryManager(*args, **kwargs)#
Bases:
ManagerCustom manager for ContentLibrary class.
- get_by_key(library_key) ContentLibrary#
Get the ContentLibrary for the given LibraryLocatorV2 key.
- class openedx.core.djangoapps.content_libraries.models.ContentLibraryPermission(*args, **kwargs)#
Bases:
ModelRow recording permissions for a content library
- ACCESS_LEVEL_CHOICES = (('admin', 'Administer users and author content'), ('author', 'Author content'), ('read', 'Read-only'))#
- ADMIN_LEVEL = 'admin'#
- AUTHOR_LEVEL = 'author'#
- exception DoesNotExist#
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned#
Bases:
MultipleObjectsReturned
- READ_LEVEL = 'read'#
- access_level#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- get_access_level_display(*, field=<django.db.models.fields.CharField: access_level>)#
- group#
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.
- group_id#
- id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- library#
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.
- library_id#
- objects = <django.db.models.manager.Manager object>#
- save(*args, **kwargs)#
Validate any constraints on the model.
We can remove this and replace it with a proper database constraint once we’re upgraded to Django 2.2+
- user#
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.
- user_id#
- class openedx.core.djangoapps.content_libraries.models.LtiGradedResource(*args, **kwargs)#
Bases:
ModelA content libraries resource launched through LTI with AGS enabled.
Essentially, an instance of this model represents a successful LTI AGS launch. This model links the profile that launched the resource with the resource itself, allowing identifcation of the link through its usage key string and user id.
- exception DoesNotExist#
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned#
Bases:
MultipleObjectsReturned
- ags_lineitem#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- objects = <openedx.core.djangoapps.content_libraries.models.LtiGradedResourceManager object>#
- profile#
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.
- profile_id#
- resource_id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- resource_title#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- update_score(weighted_earned, weighted_possible, timestamp)#
Use LTI’s score service to update the LTI platform’s gradebook.
This method synchronously send a request to the LTI platform to update the assignment score.
- usage_key#
DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!
A placeholder class that provides a way to set the attribute on the model.
- class openedx.core.djangoapps.content_libraries.models.LtiGradedResourceManager(*args, **kwargs)#
Bases:
ManagerA custom manager for the graded resources model.
- get_from_user_id(user_id, **kwds)#
Retrieve a resource for a given user id holding an lti profile.
- upsert_from_ags_launch(user, block, resource_endpoint, resource_link)#
Update or create a graded resource at AGS launch.
- class openedx.core.djangoapps.content_libraries.models.LtiProfile(*args, **kwargs)#
Bases:
ModelContent Libraries LTI’s profile for Open edX users.
Unless Anonymous, this should be a unique representation of the LTI subject (as per the client token
subidentify claim) that initiated an LTI launch through Content Libraries.- exception DoesNotExist#
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned#
Bases:
MultipleObjectsReturned
- client_id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- created_at#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)#
- get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)#
- id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- lti_resources#
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.
- objects = <openedx.core.djangoapps.content_libraries.models.LtiProfileManager object>#
- platform_id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- save(*args, **kwds)#
Get or create an edx user on save.
- subject_id#
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- property subject_url#
An local URL that is known to uniquely identify this profile.
We take advantage of the fact that platform id is required to be an URL and append paths with the reamaining keys to it.
- user#
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.
- user_id#
- class openedx.core.djangoapps.content_libraries.models.LtiProfileManager(*args, **kwargs)#
Bases:
ManagerCustom manager of LtiProfile mode.
- get_from_claims(*, iss, aud, sub)#
Get the an instance from a LTI launch claims.
- get_or_create_from_claims(*, iss, aud, sub)#
Get or create an instance from a LTI launch claims.
openedx.core.djangoapps.content_libraries.permissions module#
Permissions for Content Libraries (v2, Learning-Core-based)
- class openedx.core.djangoapps.content_libraries.permissions.HasPermissionInContentLibraryScope(permission: PermissionData, filter_keys: list[str] | None = None)#
Bases:
RuleBridgekeeper rule that checks content library permissions via the openedx-authz system.
This rule integrates the openedx-authz authorization system (backed by Casbin) with Bridgekeeper’s declarative permission system. It checks if a user has been granted a specific permission (action) through their role assignments in the authorization system.
The rule works by: 1. Querying the authorization system to find library scopes where the user has this permission 2. Parsing the library keys (org/slug) from the scopes 3. Building database filters to match ContentLibrary models with those org/slug combinations
- permission#
The permission object representing the action to check (e.g., ‘view’, ‘edit’). This is used to look up scopes in the authorization system.
- Type:
PermissionData
- filter_keys#
The Django model fields to use when building QuerySet filters. Defaults to [‘org’, ‘slug’] for ContentLibrary models.
These fields are used to construct the Q object filters that match libraries based on the parsed components from library keys in authorization scopes.
For ContentLibrary, library keys have the format ‘lib:ORG:SLUG’, which maps to: - ‘org’ -> filters on org__short_name (related Organization model) - ‘slug’ -> filters on slug field
If filtering by different fields is needed, pass a custom list. For example: - [‘org’, ‘slug’] - default for ContentLibrary (filters by org and slug) - [‘id’] - filter by primary key (for other models)
- Type:
list[str]
Examples
- Basic usage with default filter_keys:
>>> from bridgekeeper import perms >>> from openedx.core.djangoapps.content_libraries.permissions import HasPermissionInContentLibraryScope >>> >>> # Uses default filter_keys=['org', 'slug'] for ContentLibrary >>> can_view = HasPermissionInContentLibraryScope('view_library') >>> perms['libraries.view_library'] = can_view
- Compound permissions with boolean operators:
>>> from bridgekeeper.rules import Attribute >>> >>> is_active = Attribute('is_active', True) >>> is_staff = Attribute('is_staff', True) >>> can_view = HasPermissionInContentLibraryScope('view_library') >>> >>> # User must be active AND (staff OR have explicit permission) >>> perms['libraries.view_library'] = is_active & (is_staff | can_view)
- QuerySet filtering (efficient, database-level):
>>> from openedx.core.djangoapps.content_libraries.models import ContentLibrary >>> >>> # Gets all libraries user can view in a single SQL query >>> visible_libraries = perms['libraries.view_library'].filter( ... request.user, ... ContentLibrary.objects.all() ... )
- Individual object checks:
>>> library = ContentLibrary.objects.get(org__short_name='DemoX', slug='CSPROB') >>> if perms['libraries.view_library'].check(request.user, library): ... # User can view this specific library
Note
The library keys in authorization scopes must have the format ‘lib:ORG:SLUG’ to match the ContentLibrary model’s org.short_name and slug fields. For example, scope ‘lib:DemoX:CSPROB’ matches a library with org.short_name=’DemoX’ and slug=’CSPROB’.
- check(user, instance, *args, **kwargs)#
Check if user has permission for a specific object instance.
This method is used for checking permission on individual objects rather than filtering a QuerySet. It extracts the scope from the object and checks if the user has the required permission in that scope via Casbin.
- Parameters:
user – The Django user object (must have a ‘username’ attribute).
instance – The Django model instance to check permission for.
*args – Additional positional arguments (for compatibility with parent signature).
**kwargs – Additional keyword arguments (for compatibility with parent signature).
- Returns:
- True if the user has the permission in the object’s scope,
False otherwise.
- Return type:
bool
Example
>>> rule = HasPermissionInContentLibraryScope('view') >>> can_view = rule.check(user, library) >>> # Checks if user has 'view' permission in scope 'lib:DemoX:CSPROB'
- query(user)#
Convert this rule to a Django Q object for QuerySet filtering.
- Parameters:
user – The Django user object (must have a ‘username’ attribute).
- Returns:
- A Django Q object that can be used to filter a QuerySet.
The Q object combines multiple conditions using OR (|) operators, where each condition matches a library’s org and slug fields: Q(org__short_name=’OrgA’ & slug=’lib-a’) | Q(org__short_name=’OrgB’ & slug=’lib-b’)
- Return type:
Q
Example
>>> # User has 'view' permission in scopes: ['lib:OrgA:lib-a', 'lib:OrgB:lib-b'] >>> rule = HasPermissionInContentLibraryScope('view', filter_keys=['org', 'slug']) >>> q = rule.query(user) >>> # Results in: Q(org__short_name='OrgA', slug='lib-a') | Q(org__short_name='OrgB', slug='lib-b') >>> >>> # Apply to queryset >>> libraries = ContentLibrary.objects.filter(q) >>> # SQL: SELECT * FROM content_library >>> # WHERE (org.short_name='OrgA' AND slug='lib-a') >>> # OR (org.short_name='OrgB' AND slug='lib-b')
openedx.core.djangoapps.content_libraries.signal_handlers module#
Content library signal handlers.
- openedx.core.djangoapps.content_libraries.signal_handlers.library_collection_deleted(sender, instance, **kwargs)#
Raises LIBRARY_COLLECTION_DELETED for the deleted Collection.
- openedx.core.djangoapps.content_libraries.signal_handlers.library_collection_entities_changed(sender, instance, action, pk_set, **kwargs)#
Sends a CONTENT_OBJECT_ASSOCIATIONS_CHANGED event for components added/removed/cleared from a collection.
- openedx.core.djangoapps.content_libraries.signal_handlers.library_collection_entity_deleted(sender, instance, **kwargs)#
Sends a CONTENT_OBJECT_ASSOCIATIONS_CHANGED event for components removed from a collection.
- openedx.core.djangoapps.content_libraries.signal_handlers.library_collection_entity_saved(sender, instance, created, **kwargs)#
Sends a CONTENT_OBJECT_ASSOCIATIONS_CHANGED event for components added to a collection.
- openedx.core.djangoapps.content_libraries.signal_handlers.library_collection_saved(sender, instance, created, **kwargs)#
Raises LIBRARY_COLLECTION_CREATED if the Collection is new, or LIBRARY_COLLECTION_UPDATED if updated an existing Collection.
- openedx.core.djangoapps.content_libraries.signal_handlers.score_changed_handler(sender, **kwargs)#
Match the score event to an LTI resource and update.
openedx.core.djangoapps.content_libraries.tasks module#
Celery tasks for Content Libraries.
Architecture note:
Several functions in this file manage the copying/updating of blocks in modulestore and learning core. These operations should only be performed within the context of CMS. However, due to existing edx-platform code structure, we’ve had to define the functions in shared source tree (openedx/) and the tasks are registered in both LMS and CMS.
To ensure that we’re not accidentally importing things from learning core in the LMS context, we use ensure_cms throughout this module.
A longer-term solution to this issue would be to move the content_libraries app to cms: openedx/edx-platform#33428
- class openedx.core.djangoapps.content_libraries.tasks.LibraryBackupTask#
Bases:
UserTaskBase class for tasks related with Library backup functionality.
- NAME_PREFIX = 'Library Learning Package Backup'#
- classmethod generate_name(arguments_dict) str#
Create a name for this particular backup task instance.
Should be both: a. semi human-friendly b. something we can query in order to determine whether the library has a task in progress
- Parameters:
arguments_dict (dict) – The arguments given to the task function
- Returns:
The generated name
- Return type:
str
- ignore_result = False#
If enabled the worker won’t store task state and return values for this task. Defaults to the :setting:`task_ignore_result` setting.
- priority = None#
Default task priority.
- rate_limit = None#
None(no rate limit), ‘100/s’ (hundred tasks a second), ‘100/m’ (hundred tasks a minute),`’100/h’` (hundred tasks an hour)- Type:
Rate limit for this task type. Examples
- reject_on_worker_lost = None#
Even if
acks_lateis enabled, the worker will acknowledge tasks when the worker process executing them abruptly exits or is signaled (e.g., :sig:`KILL`/:sig:`INT`, etc).Setting this to true allows the message to be re-queued instead, so that the task will execute again by the same worker, or another worker.
Warning: Enabling this can cause message loops; make sure you know what you’re doing.
- request_stack = <celery.utils.threads._LocalStack object>#
Task request stack, the current request will be the topmost.
- serializer = 'json'#
The name of a serializer that are registered with
kombu.serialization.registry. Default is ‘json’.
- store_errors_even_if_ignored = True#
When enabled errors will be stored even if the task is otherwise configured to ignore results.
- track_started = True#
If enabled the task will report its status as ‘started’ when the task is executed by a worker. Disabled by default as the normal behavior is to not report that level of granularity. Tasks are either pending, finished, or waiting to be retried.
Having a ‘started’ status can be useful for when there are long running tasks and there’s a need to report what task is currently running.
The application default can be overridden using the :setting:`task_track_started` setting.
- typing = True#
Enable argument checking. You can set this to false if you don’t want the signature to be checked when calling the task. Defaults to
app.strict_typing.
- exception openedx.core.djangoapps.content_libraries.tasks.LibraryRestoreLoadError(message, logfile=None)#
Bases:
Exception
- class openedx.core.djangoapps.content_libraries.tasks.LibraryRestoreTask#
Bases:
UserTaskBase class for library restore tasks.
- ARTIFACT_NAMES = {'Failed': 'Error log', 'Succeeded': 'Library Restore'}#
- ERROR_LOG_ARTIFACT_NAME = 'Error log'#
- NAME_PREFIX = 'Library Learning Package Restore'#
- fail_with_error_log(logfile) None#
Helper method to create an error log artifact and fail the task.
- Parameters:
logfile (io.StringIO) – The error log content
- classmethod generate_name(arguments_dict)#
Generate a name for the corresponding
UserTaskStatusmodel instance.Should be implemented by each subclass to generate a meaningful name from the task parameters. Defaults to the name of the task function.
- ignore_result = False#
If enabled the worker won’t store task state and return values for this task. Defaults to the :setting:`task_ignore_result` setting.
- load_learning_package(storage_path, user)#
Load learning package from a backup file in storage.
- Parameters:
storage_path (str) – The path to the backup file in storage
- Returns:
The result of loading the learning package, including status and info
- Return type:
dict
- Raises:
LibraryRestoreLoadError – If there is an error loading the learning package
- priority = None#
Default task priority.
- rate_limit = None#
None(no rate limit), ‘100/s’ (hundred tasks a second), ‘100/m’ (hundred tasks a minute),`’100/h’` (hundred tasks an hour)- Type:
Rate limit for this task type. Examples
- reject_on_worker_lost = None#
Even if
acks_lateis enabled, the worker will acknowledge tasks when the worker process executing them abruptly exits or is signaled (e.g., :sig:`KILL`/:sig:`INT`, etc).Setting this to true allows the message to be re-queued instead, so that the task will execute again by the same worker, or another worker.
Warning: Enabling this can cause message loops; make sure you know what you’re doing.
- request_stack = <celery.utils.threads._LocalStack object>#
Task request stack, the current request will be the topmost.
- serializer = 'json'#
The name of a serializer that are registered with
kombu.serialization.registry. Default is ‘json’.
- store_errors_even_if_ignored = True#
When enabled errors will be stored even if the task is otherwise configured to ignore results.
- track_started = True#
If enabled the task will report its status as ‘started’ when the task is executed by a worker. Disabled by default as the normal behavior is to not report that level of granularity. Tasks are either pending, finished, or waiting to be retried.
Having a ‘started’ status can be useful for when there are long running tasks and there’s a need to report what task is currently running.
The application default can be overridden using the :setting:`task_track_started` setting.
- typing = True#
Enable argument checking. You can set this to false if you don’t want the signature to be checked when calling the task. Defaults to
app.strict_typing.
- class openedx.core.djangoapps.content_libraries.tasks.LibrarySyncChildrenTask#
Bases:
UserTaskBase class for tasks which operate upon library_content children.
- classmethod generate_name(arguments_dict) str#
Create a name for this particular import task instance.
Should be both: a. semi human-friendly b. something we can query in order to determine whether the dest block has a task in progress
- Parameters:
arguments_dict (dict) – The arguments given to the task function
- ignore_result = False#
If enabled the worker won’t store task state and return values for this task. Defaults to the :setting:`task_ignore_result` setting.
- priority = None#
Default task priority.
- rate_limit = None#
None(no rate limit), ‘100/s’ (hundred tasks a second), ‘100/m’ (hundred tasks a minute),`’100/h’` (hundred tasks an hour)- Type:
Rate limit for this task type. Examples
- reject_on_worker_lost = None#
Even if
acks_lateis enabled, the worker will acknowledge tasks when the worker process executing them abruptly exits or is signaled (e.g., :sig:`KILL`/:sig:`INT`, etc).Setting this to true allows the message to be re-queued instead, so that the task will execute again by the same worker, or another worker.
Warning: Enabling this can cause message loops; make sure you know what you’re doing.
- request_stack = <celery.utils.threads._LocalStack object>#
Task request stack, the current request will be the topmost.
- serializer = 'json'#
The name of a serializer that are registered with
kombu.serialization.registry. Default is ‘json’.
- store_errors_even_if_ignored = True#
When enabled errors will be stored even if the task is otherwise configured to ignore results.
- track_started = True#
If enabled the task will report its status as ‘started’ when the task is executed by a worker. Disabled by default as the normal behavior is to not report that level of granularity. Tasks are either pending, finished, or waiting to be retried.
Having a ‘started’ status can be useful for when there are long running tasks and there’s a need to report what task is currently running.
The application default can be overridden using the :setting:`task_track_started` setting.
- typing = True#
Enable argument checking. You can set this to false if you don’t want the signature to be checked when calling the task. Defaults to
app.strict_typing.
- openedx.core.djangoapps.content_libraries.tasks.wait_for_post_publish_events(publish_log: PublishLog, library_key: LibraryLocatorV2)#
After publishing some changes, trigger the required event handlers (e.g. update the search index). Try to wait for that to complete before returning, up to some reasonable timeout, and then finish anything remaining asynchonrously.
- openedx.core.djangoapps.content_libraries.tasks.wait_for_post_revert_events(draft_change_log: DraftChangeLog, library_key: LibraryLocatorV2)#
After discard all changes in a library, trigger the required event handlers (e.g. update the search index). Try to wait for that to complete before returning, up to some reasonable timeout, and then finish anything remaining asynchonrously.