-
Notifications
You must be signed in to change notification settings - Fork 23
Emit events when a learning package is modified [FC-0117] #543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3f936dc
f20a26b
0f39f27
296b74c
88f3791
dc93d73
160a649
72a9890
eb7b160
09562bc
68ebddb
15aba54
5e11a12
7ad1e79
f2e3eba
c9ed092
df3adc3
4544647
bc66b61
9afae55
fa81324
140e1b3
d370852
f17cec5
627c574
7b62c3e
d3537e4
ff15eb2
3902b85
a53166d
e42144b
26683ff
5ff0496
1fb4854
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """Signal handlers for collections-related updates.""" | ||
|
|
||
| from functools import partial | ||
|
|
||
| from django.db import transaction | ||
| from django.dispatch import receiver | ||
|
|
||
| from ..publishing.signals import ENTITIES_DRAFT_CHANGED, DraftChangeLogEventData, UserAttributionEventData | ||
| from .tasks import emit_collections_changed_for_entity_changes_task | ||
|
|
||
|
|
||
| @receiver(ENTITIES_DRAFT_CHANGED) | ||
| def on_entities_changed( | ||
| change_log: DraftChangeLogEventData, | ||
| changed_by: UserAttributionEventData, | ||
| **kwargs, | ||
| ): | ||
| """ | ||
| When entity drafts are deleted or restored, notify affected collections. | ||
|
|
||
| Dispatches a task to emit COLLECTION_CHANGED for any | ||
| collections that contain the changed entities. | ||
| """ | ||
| removed_entity_ids = [record.entity_id for record in change_log.changes if record.new_version_id is None] | ||
| # old_version_id=None covers both brand-new entities and restored soft-deletes; we can't distinguish | ||
| # them here without a DB query. The task is a no-op for new entities (not yet in any collection). | ||
| # TODO: if ChangeLogRecordData gains a 'restored' flag, filter to only restored entities here. | ||
| # (Newly-created entities cannot be part of collections yet, so we only care about entities that | ||
| # were previously in collections, then deleted and then restored.) | ||
| added_entity_ids = [ | ||
| record.entity_id | ||
| for record in change_log.changes | ||
| if record.old_version_id is None and record.new_version_id is not None | ||
| ] | ||
|
|
||
| if not removed_entity_ids and not added_entity_ids: | ||
| return | ||
|
|
||
| transaction.on_commit( | ||
| partial( | ||
| emit_collections_changed_for_entity_changes_task.delay, | ||
| removed_entity_ids=removed_entity_ids, | ||
| added_entity_ids=added_entity_ids, | ||
| user_id=changed_by.user_id, | ||
| ) | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| """ | ||
| Low-level events/signals emitted by openedx_content | ||
| """ | ||
|
|
||
| from attrs import define, field | ||
| from openedx_events.tooling import OpenEdxPublicSignal # type: ignore[import-untyped] | ||
|
|
||
| from ..publishing.models.publishable_entity import PublishableEntity | ||
| from ..publishing.signals import LearningPackageEventData, UserAttributionEventData | ||
|
|
||
| # Public API available via openedx_content.api | ||
| __all__ = [ | ||
| # All event data structures should end with "...Data": | ||
| "CollectionChangeData", | ||
| # All events: | ||
| "COLLECTION_CHANGED", | ||
| ] | ||
|
|
||
|
|
||
| @define | ||
| class CollectionChangeData: | ||
| """Summary of changes to a collection, for event purposes""" | ||
|
|
||
| collection_id: int | ||
| collection_code: str | ||
| created: bool = False | ||
| """The collection is newly-created, or un-deleted. Some entities may be added simultaneously.""" | ||
| metadata_modified: bool = False | ||
|
ormsbee marked this conversation as resolved.
|
||
| """The collection's title/description has changed. Does not indicate whether or not entities were added/removed.""" | ||
| deleted: bool = False | ||
| """ | ||
| The collection has been deleted. When this is true, the entities_removed list will have all entity IDs. | ||
| Does not distinguish between "soft" and "hard" deletion. | ||
| """ | ||
| entities_added: list[PublishableEntity.ID] = field(factory=list) | ||
| entities_removed: list[PublishableEntity.ID] = field(factory=list) | ||
|
|
||
|
|
||
| COLLECTION_CHANGED = OpenEdxPublicSignal( | ||
| event_type="org.openedx.content.collections.collection_changed.v1", | ||
| data={ | ||
| "learning_package": LearningPackageEventData, | ||
| "changed_by": UserAttributionEventData, | ||
| "change": CollectionChangeData, | ||
|
Comment on lines
+42
to
+44
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am using multiple Edit: based on the additional info I posted there, it should be completely fine. But any automatic parsing of the signal documentation may have incomplete type info (or rather, slightly more incomplete than it already is, since it already lacks the dict key info for all events). |
||
| }, | ||
| ) | ||
| """ | ||
| A ``Collection`` has been created, modified, or deleted, or its entities have | ||
| changed. | ||
|
|
||
| This is a low-level batch event. It does not have any course or library context | ||
| information available. It does not distinguish between Containers, Components, | ||
| or other entity types. | ||
|
|
||
| 💾 This event is only emitted after any transaction has been committed. | ||
|
|
||
| ⏳ This **batch** event is emitted **synchronously**. Handlers that do anything | ||
| per-entity or that is possibly slow should dispatch an asynchronous task for | ||
| processing the event. | ||
| """ | ||
|
|
||
| # Note: at present, the openedx_tagging code (in this repo) emits a | ||
| # CONTENT_OBJECT_ASSOCIATIONS_CHANGED event whenever an entity's tags change. | ||
| # But we do NOT emit the same event when an entity's collections change; rather | ||
| # we expect code in the platform to listen for COLLECTION_CHANGED and then | ||
| # re-emit '...ASSOCIATIONS_CHANGED' as needed. | ||
| # The reason we don't emit the '...ASSOCIATIONS_CHANGED' event here | ||
| # is simple: we know the entity IDs but not their opaque keys, and all of the | ||
| # code that listens for that event expects the entity's opaque keys. | ||
| # The tagging code can do it here because the `object_id` in the tagging models | ||
| # _is_ the opaque key ("lb:..."), but the collections code is too low-level to | ||
| # know about opaque keys of the entities. We don't even know which learning | ||
| # context (which content library) a given entity is in. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helper would not be necessary if openedx/openedx-events#570 is accepted, and then we could just use that.