diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 855dcae7..65d1abbb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,8 +11,28 @@ Change Log .. There should always be an "Unreleased" section for changes pending release. + + Unreleased ----------- +__________ + + + +[9.14.0] - 2024-09-12 +--------------------- + +Added +~~~~~ + +* Adds event ``CONTENT_OBJECT_ASSOCIATIONS_CHANGED`` +* Added new ``LIBRARY_COLLECTION_CREATED``, ``LIBRARY_COLLECTION_UPDATED`` and ``LIBRARY_COLLECTION_DELETED`` events in content_authoring. +* Adds ``ContentObjectChangedData``, which inherits from ContentObjectData and adds an optional list of string ``changes``. + +Deprecated +~~~~~~~~~~ + +* Deprecated event ``CONTENT_OBJECT_TAGS_CHANGED`` in favor of ``CONTENT_OBJECT_ASSOCIATIONS_CHANGED`` + Plan to remove after Sumac. [9.13.0] - 2024-09-05 --------------------- diff --git a/openedx_events/__init__.py b/openedx_events/__init__.py index 445806a0..40b95950 100644 --- a/openedx_events/__init__.py +++ b/openedx_events/__init__.py @@ -5,4 +5,4 @@ more information about the project. """ -__version__ = "9.13.0" +__version__ = "9.14.0" diff --git a/openedx_events/content_authoring/data.py b/openedx_events/content_authoring/data.py index 1483ddbc..4e76bcd7 100644 --- a/openedx_events/content_authoring/data.py +++ b/openedx_events/content_authoring/data.py @@ -185,7 +185,7 @@ class LibraryBlockData: @attr.s(frozen=True) class ContentObjectData: """ - Data about changed content object. + Data about a content object. Arguments: object_id (str): identifier of the Content object. This represents the id of the course or library block @@ -194,3 +194,34 @@ class ContentObjectData: """ object_id = attr.ib(type=str) + + +@attr.s(frozen=True) +class ContentObjectChangedData(ContentObjectData): + """ + Data about a changed content object. + + Arguments: + object_id (str): identifier of the Content object. This represents the id of the course or library block + as a string. For example: + block-v1:SampleTaxonomyOrg2+STC1+2023_1+type@vertical+block@f8de78f0897049ce997777a3a31b6ea0 + + changes: list of changes made to this ContentObject, e.g. "tags", "collections" + If list is empty, assume everything has changed. + """ + + changes = attr.ib(type=List[str], factory=list) + + +@attr.s(frozen=True) +class LibraryCollectionData: + """ + Data about changed content library Collection. + + Arguments: + library_key (LibraryLocatorV2): a key that represents a Blockstore-based content library. + collection_key (str): identifies the collection within the library's learning package + """ + + library_key = attr.ib(type=LibraryLocatorV2) + collection_key = attr.ib(type=str) diff --git a/openedx_events/content_authoring/signals.py b/openedx_events/content_authoring/signals.py index 495d14d9..dc323827 100644 --- a/openedx_events/content_authoring/signals.py +++ b/openedx_events/content_authoring/signals.py @@ -10,11 +10,13 @@ from openedx_events.content_authoring.data import ( CertificateConfigData, ContentLibraryData, + ContentObjectChangedData, ContentObjectData, CourseCatalogData, CourseData, DuplicatedXBlockData, LibraryBlockData, + LibraryCollectionData, XBlockData, ) from openedx_events.tooling import OpenEdxPublicSignal @@ -200,9 +202,21 @@ } ) +# .. event_type: org.openedx.content_authoring.content.object.associations.changed.v1 +# .. event_name: CONTENT_OBJECT_ASSOCIATIONS_CHANGED +# .. event_description: emitted when an object's associations are changed, e.g tags, collections +# .. event_data: ContentObjectData +CONTENT_OBJECT_ASSOCIATIONS_CHANGED = OpenEdxPublicSignal( + event_type="org.openedx.content_authoring.content.object.associations.changed.v1", + data={ + "content_object": ContentObjectChangedData + } +) + # .. event_type: org.openedx.content_authoring.content.object.tags.changed.v1 # .. event_name: CONTENT_OBJECT_TAGS_CHANGED # .. event_description: emitted when an object's tags are changed +# DEPRECATED: please use CONTENT_OBJECT_ASSOCIATIONS_CHANGED instead. # .. event_data: ContentObjectData CONTENT_OBJECT_TAGS_CHANGED = OpenEdxPublicSignal( event_type="org.openedx.content_authoring.content.object.tags.changed.v1", @@ -210,3 +224,36 @@ "content_object": ContentObjectData } ) + +# .. event_type: org.openedx.content_authoring.content_library.collection.created.v1 +# .. event_name: LIBRARY_COLLECTION_CREATED +# .. event_description: emitted when a content library collection is created +# .. event_data: LibraryCollectionData +LIBRARY_COLLECTION_CREATED = OpenEdxPublicSignal( + event_type="org.openedx.content_authoring.content_library.collection.created.v1", + data={ + "library_collection": LibraryCollectionData + } +) + +# .. event_type: org.openedx.content_authoring.content_library.collection.updated.v1 +# .. event_name: LIBRARY_COLLECTION_UPDATED +# .. event_description: emitted when when a content library collection is updated +# .. event_data: LibraryCollectionData +LIBRARY_COLLECTION_UPDATED = OpenEdxPublicSignal( + event_type="org.openedx.content_authoring.content_library.collection.updated.v1", + data={ + "library_collection": LibraryCollectionData + } +) + +# .. event_type: org.openedx.content_authoring.content_library.collection.deleted.v1 +# .. event_name: LIBRARY_COLLECTION_DELETED +# .. event_description: emitted when an when a content library collection is deleted +# .. event_data: LibraryCollectionData +LIBRARY_COLLECTION_DELETED = OpenEdxPublicSignal( + event_type="org.openedx.content_authoring.content_library.collection.deleted.v1", + data={ + "library_collection": LibraryCollectionData + } +) diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc new file mode 100644 index 00000000..5f3cfb2c --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc @@ -0,0 +1,28 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "content_object", + "type": { + "name": "ContentObjectChangedData", + "type": "record", + "fields": [ + { + "name": "object_id", + "type": "string" + }, + { + "name": "changes", + "type": { + "type": "array", + "items": "string" + } + } + ] + } + } + ], + "namespace": "org.openedx.content_authoring.content.object.associations.changed.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+created+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+created+v1_schema.avsc new file mode 100644 index 00000000..58b77a50 --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+created+v1_schema.avsc @@ -0,0 +1,25 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "library_collection", + "type": { + "name": "LibraryCollectionData", + "type": "record", + "fields": [ + { + "name": "library_key", + "type": "string" + }, + { + "name": "collection_key", + "type": "string" + } + ] + } + } + ], + "namespace": "org.openedx.content_authoring.content_library.collection.created.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+deleted+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+deleted+v1_schema.avsc new file mode 100644 index 00000000..473d4163 --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+deleted+v1_schema.avsc @@ -0,0 +1,25 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "library_collection", + "type": { + "name": "LibraryCollectionData", + "type": "record", + "fields": [ + { + "name": "library_key", + "type": "string" + }, + { + "name": "collection_key", + "type": "string" + } + ] + } + } + ], + "namespace": "org.openedx.content_authoring.content_library.collection.deleted.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+updated+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+updated+v1_schema.avsc new file mode 100644 index 00000000..54733048 --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content_library+collection+updated+v1_schema.avsc @@ -0,0 +1,25 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "library_collection", + "type": { + "name": "LibraryCollectionData", + "type": "record", + "fields": [ + { + "name": "library_key", + "type": "string" + }, + { + "name": "collection_key", + "type": "string" + } + ] + } + } + ], + "namespace": "org.openedx.content_authoring.content_library.collection.updated.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/test_avro.py b/openedx_events/event_bus/avro/tests/test_avro.py index 4d564b27..87634067 100644 --- a/openedx_events/event_bus/avro/tests/test_avro.py +++ b/openedx_events/event_bus/avro/tests/test_avro.py @@ -108,6 +108,7 @@ def generate_test_event_data_for_data_type(data_type): # pragma: no cover LibraryLocatorV2: LibraryLocatorV2.from_string('lib:MITx:reallyhardproblems'), LibraryUsageLocatorV2: LibraryUsageLocatorV2.from_string('lb:MITx:reallyhardproblems:problem:problem1'), List[int]: [1, 2, 3], + List[str]: ["hi", "there"], datetime: datetime.now(), CCXLocator: CCXLocator(org='edx', course='DemoX', run='Demo_course', ccx='1'), UUID: uuid4(),