feat: hook xblock publish, delete and duplicate openedx-events (#31350)
This commit is contained in:
@@ -13,7 +13,12 @@ from django.dispatch import receiver
|
||||
from edx_toggles.toggles import SettingToggle
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx_events.content_authoring.data import CourseCatalogData, CourseScheduleData
|
||||
from openedx_events.content_authoring.signals import COURSE_CATALOG_INFO_CHANGED
|
||||
from openedx_events.content_authoring.signals import (
|
||||
COURSE_CATALOG_INFO_CHANGED,
|
||||
XBLOCK_DELETED,
|
||||
XBLOCK_DUPLICATED,
|
||||
XBLOCK_PUBLISHED,
|
||||
)
|
||||
from openedx_events.event_bus import get_producer
|
||||
from pytz import UTC
|
||||
|
||||
@@ -166,6 +171,42 @@ def listen_for_course_catalog_info_changed(sender, signal, **kwargs):
|
||||
)
|
||||
|
||||
|
||||
@receiver(XBLOCK_PUBLISHED)
|
||||
def listen_for_xblock_published(sender, signal, **kwargs):
|
||||
"""
|
||||
Publish XBLOCK_PUBLISHED signals onto the event bus.
|
||||
"""
|
||||
get_producer().send(
|
||||
signal=XBLOCK_PUBLISHED, topic='xblock-published',
|
||||
event_key_field='xblock_info.usage_key', event_data={'xblock_info': kwargs['xblock_info']},
|
||||
event_metadata=kwargs['metadata'],
|
||||
)
|
||||
|
||||
|
||||
@receiver(XBLOCK_DELETED)
|
||||
def listen_for_xblock_deleted(sender, signal, **kwargs):
|
||||
"""
|
||||
Publish XBLOCK_DELETED signals onto the event bus.
|
||||
"""
|
||||
get_producer().send(
|
||||
signal=XBLOCK_DELETED, topic='xblock-deleted',
|
||||
event_key_field='xblock_info.usage_key', event_data={'xblock_info': kwargs['xblock_info']},
|
||||
event_metadata=kwargs['metadata'],
|
||||
)
|
||||
|
||||
|
||||
@receiver(XBLOCK_DUPLICATED)
|
||||
def listen_for_xblock_duplicated(sender, signal, **kwargs):
|
||||
"""
|
||||
Publish XBLOCK_DUPLICATED signals onto the event bus.
|
||||
"""
|
||||
get_producer().send(
|
||||
signal=XBLOCK_DUPLICATED, topic='xblock-duplicated',
|
||||
event_key_field='xblock_info.usage_key', event_data={'xblock_info': kwargs['xblock_info']},
|
||||
event_metadata=kwargs['metadata'],
|
||||
)
|
||||
|
||||
|
||||
@receiver(SignalHandler.course_deleted)
|
||||
def listen_for_course_delete(sender, course_key, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
|
||||
@@ -11,9 +11,12 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest
|
||||
from django.utils.timezone import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from edx_django_utils.plugins import pluggable_override
|
||||
from openedx_events.content_authoring.data import DuplicatedXBlockData
|
||||
from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED
|
||||
from edx_proctoring.api import (
|
||||
does_backend_support_onboarding,
|
||||
get_exam_by_content_id,
|
||||
@@ -959,6 +962,16 @@ def _duplicate_block(parent_usage_key, duplicate_source_usage_key, user, display
|
||||
parent.children.append(dest_block.location)
|
||||
store.update_item(parent, user.id)
|
||||
|
||||
# .. event_implemented_name: XBLOCK_DUPLICATED
|
||||
XBLOCK_DUPLICATED.send_event(
|
||||
time=datetime.now(timezone.utc),
|
||||
xblock_info=DuplicatedXBlockData(
|
||||
usage_key=dest_block.location,
|
||||
block_type=dest_block.location.block_type,
|
||||
source_usage_key=duplicate_source_usage_key,
|
||||
)
|
||||
)
|
||||
|
||||
return dest_block.location
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ from django.http import Http404
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from openedx_events.content_authoring.data import DuplicatedXBlockData
|
||||
from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED
|
||||
from openedx_events.tests.utils import OpenEdxEventsTestMixin
|
||||
from edx_proctoring.exceptions import ProctoredExamNotFoundException
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.asides import AsideUsageKeyV2
|
||||
@@ -550,6 +553,7 @@ class DuplicateHelper:
|
||||
self._check_equality(source_usage_key, usage_key, parent_usage_key, check_asides=check_asides),
|
||||
"Duplicated item differs from original"
|
||||
)
|
||||
return usage_key
|
||||
|
||||
def _check_equality(self, source_usage_key, duplicate_usage_key, parent_usage_key=None, check_asides=False,
|
||||
is_child=False):
|
||||
@@ -642,11 +646,25 @@ class DuplicateHelper:
|
||||
return self.response_usage_key(resp)
|
||||
|
||||
|
||||
class TestDuplicateItem(ItemTest, DuplicateHelper):
|
||||
class TestDuplicateItem(ItemTest, DuplicateHelper, OpenEdxEventsTestMixin):
|
||||
"""
|
||||
Test the duplicate method.
|
||||
"""
|
||||
|
||||
ENABLED_OPENEDX_EVENTS = [
|
||||
"org.openedx.content_authoring.xblock.duplicated.v1",
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""
|
||||
Set up class method for the Test class.
|
||||
This method starts manually events isolation. Explanation here:
|
||||
openedx/core/djangoapps/user_authn/views/tests/test_events.py#L44
|
||||
"""
|
||||
super().setUpClass()
|
||||
cls.start_events_isolation()
|
||||
|
||||
def setUp(self):
|
||||
""" Creates the test course structure and a few components to 'duplicate'. """
|
||||
super().setUp()
|
||||
@@ -684,6 +702,27 @@ class TestDuplicateItem(ItemTest, DuplicateHelper):
|
||||
self._duplicate_and_verify(self.seq_usage_key, self.chapter_usage_key)
|
||||
self._duplicate_and_verify(self.chapter_usage_key, self.usage_key)
|
||||
|
||||
def test_duplicate_event(self):
|
||||
"""
|
||||
Check that XBLOCK_DUPLICATED event is sent when xblock is duplicated.
|
||||
"""
|
||||
event_receiver = Mock()
|
||||
XBLOCK_DUPLICATED.connect(event_receiver)
|
||||
usage_key = self._duplicate_and_verify(self.vert_usage_key, self.seq_usage_key)
|
||||
event_receiver.assert_called()
|
||||
self.assertDictContainsSubset(
|
||||
{
|
||||
"signal": XBLOCK_DUPLICATED,
|
||||
"sender": None,
|
||||
"xblock_info": DuplicatedXBlockData(
|
||||
usage_key=usage_key,
|
||||
block_type=usage_key.block_type,
|
||||
source_usage_key=self.vert_usage_key,
|
||||
),
|
||||
},
|
||||
event_receiver.call_args.kwargs
|
||||
)
|
||||
|
||||
def test_ordering(self):
|
||||
"""
|
||||
Tests the a duplicated xblock appears immediately after its source
|
||||
|
||||
Reference in New Issue
Block a user