From b46d149561bc7e3f50dd59793b5158836fad217b Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Fri, 28 Jul 2023 15:47:16 +0200 Subject: [PATCH 1/7] feat: use event producer config Replace openedx_event signal handlers with new producer config to push to event bus --- .../contentstore/signals/handlers.py | 62 +------------- cms/envs/common.py | 29 +++++++ cms/envs/devstack.py | 11 --- lms/djangoapps/certificates/signals.py | 18 ---- .../certificates/tests/test_signals.py | 82 ------------------- lms/envs/common.py | 20 +++++ requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 3 +- requirements/edx/doc.txt | 4 +- requirements/edx/kernel.in | 3 +- requirements/edx/testing.txt | 2 +- 11 files changed, 58 insertions(+), 178 deletions(-) diff --git a/cms/djangoapps/contentstore/signals/handlers.py b/cms/djangoapps/contentstore/signals/handlers.py index fec46b6b7484..20c14089e0a6 100644 --- a/cms/djangoapps/contentstore/signals/handlers.py +++ b/cms/djangoapps/contentstore/signals/handlers.py @@ -13,13 +13,7 @@ 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, - XBLOCK_DELETED, - XBLOCK_DUPLICATED, - XBLOCK_PUBLISHED, -) -from openedx_events.event_bus import get_producer +from openedx_events.content_authoring.signals import COURSE_CATALOG_INFO_CHANGED from pytz import UTC from cms.djangoapps.contentstore.courseware_index import ( @@ -159,60 +153,6 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable= transaction.on_commit(lambda: emit_catalog_info_changed_signal(course_key)) -@receiver(COURSE_CATALOG_INFO_CHANGED) -def listen_for_course_catalog_info_changed(sender, signal, **kwargs): - """ - Publish COURSE_CATALOG_INFO_CHANGED signals onto the event bus. - """ - get_producer().send( - signal=COURSE_CATALOG_INFO_CHANGED, topic='course-catalog-info-changed', - event_key_field='catalog_info.course_key', event_data={'catalog_info': kwargs['catalog_info']}, - event_metadata=kwargs['metadata'], - ) - - -@receiver(XBLOCK_PUBLISHED) -def listen_for_xblock_published(sender, signal, **kwargs): - """ - Publish XBLOCK_PUBLISHED signals onto the event bus. - """ - if settings.FEATURES.get("ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS"): - topic = getattr(settings, "EVENT_BUS_XBLOCK_LIFECYCLE_TOPIC", "course-authoring-xblock-lifecycle") - get_producer().send( - signal=XBLOCK_PUBLISHED, topic=topic, - 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. - """ - if settings.FEATURES.get("ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS"): - topic = getattr(settings, "EVENT_BUS_XBLOCK_LIFECYCLE_TOPIC", "course-authoring-xblock-lifecycle") - get_producer().send( - signal=XBLOCK_DELETED, topic=topic, - 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. - """ - if settings.FEATURES.get("ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS"): - topic = getattr(settings, "EVENT_BUS_XBLOCK_LIFECYCLE_TOPIC", "course-authoring-xblock-lifecycle") - get_producer().send( - signal=XBLOCK_DUPLICATED, topic=topic, - 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 """ diff --git a/cms/envs/common.py b/cms/envs/common.py index 12b982d95d9b..e511a9115e0f 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -1789,6 +1789,9 @@ # Blockstore 'blockstore.apps.bundles', + + # Openedx events + 'openedx_events', ] @@ -2725,3 +2728,29 @@ DISCUSSIONS_INCONTEXT_FEEDBACK_URL = '' DISCUSSIONS_INCONTEXT_LEARNMORE_URL = '' + +######################## Event bus producer config ######################## + +# .. setting_name: EVENT_BUS_PRODUCER_CONFIG +# .. setting_default: {} +# .. setting_description: Dictionary of event_types mapped to lists of dictionaries containing topic related configuration. +# Each topic configuration dictionary contains +# * a topic/stream name called `topic` where the event will be pushed to. +# * a flag called `enabled` denoting whether the event will be published to the topic. +# * `event_key_field` which is a period-delimited string path to event data field to use as event key. +# Note: The topic names should not include environment prefix as it will be dynamically added based on +# EVENT_BUS_TOPIC_PREFIX setting. +EVENT_BUS_PRODUCER_CONFIG = { + 'org.openedx.content_authoring.course.catalog_info.changed.v1': [ + {'topic': 'course-catalog-info-changed', 'event_key_field': 'catalog_info.course_key', 'enabled': True}, + ], + 'org.openedx.content_authoring.xblock.published.v1': [ + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + ], + 'org.openedx.content_authoring.xblock.deleted.v1': [ + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + ], + 'org.openedx.content_authoring.xblock.duplicated.v1': [ + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + ], +} diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 4170af3d390e..3771ee06443d 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -293,21 +293,10 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing CREDENTIALS_PUBLIC_SERVICE_URL = 'http://localhost:18150' #################### Event bus backend ######################## -# .. toggle_name: FEATURES['ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS'] -# .. toggle_implementation: DjangoSetting -# .. toggle_default: False -# .. toggle_description: Temporary configuration which enables sending xblock events over the event bus. -# .. toggle_use_cases: open_edx -# .. toggle_creation_date: 2023-02-21 -# .. toggle_warning: For consistency in user experience, keep the value in sync with the setting of the same name -# in the LMS and CMS. -# .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/31813' -FEATURES['ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS'] = True EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer' EVENT_BUS_REDIS_CONNECTION_URL = 'redis://:password@edx.devstack.redis:6379/' EVENT_BUS_TOPIC_PREFIX = 'dev' EVENT_BUS_CONSUMER = 'edx_event_bus_redis.RedisEventConsumer' -EVENT_BUS_XBLOCK_LIFECYCLE_TOPIC = 'course-authoring-xblock-lifecycle' ################# New settings must go ABOVE this line ################# ######################################################################## diff --git a/lms/djangoapps/certificates/signals.py b/lms/djangoapps/certificates/signals.py index 676c10fb9c8f..28e68e340253 100644 --- a/lms/djangoapps/certificates/signals.py +++ b/lms/djangoapps/certificates/signals.py @@ -6,12 +6,10 @@ from django.db.models.signals import post_save from django.dispatch import receiver -from openedx_events.event_bus import get_producer from common.djangoapps.course_modes import api as modes_api from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.signals import ENROLLMENT_TRACK_UPDATED -from lms.djangoapps.certificates.config import SEND_CERTIFICATE_CREATED_SIGNAL from lms.djangoapps.certificates.generation_handler import ( CertificateGenerationNotAllowed, generate_allowlist_certificate_task, @@ -32,7 +30,6 @@ COURSE_GRADE_NOW_PASSED, LEARNER_NOW_VERIFIED ) -from openedx_events.learning.signals import CERTIFICATE_CREATED log = logging.getLogger(__name__) @@ -159,18 +156,3 @@ def _listen_for_enrollment_mode_change(sender, user, course_key, mode, **kwargs) course_key, ) return False - - -@receiver(CERTIFICATE_CREATED) -def listen_for_certificate_created_event(sender, signal, **kwargs): - """ - Publish `CERTIFICATE_CREATED` events to the event bus. - """ - if SEND_CERTIFICATE_CREATED_SIGNAL.is_enabled(): - get_producer().send( - signal=CERTIFICATE_CREATED, - topic='learning-certificate-lifecycle', - event_key_field='certificate.course.course_key', - event_data={'certificate': kwargs['certificate']}, - event_metadata=kwargs['metadata'] - ) diff --git a/lms/djangoapps/certificates/tests/test_signals.py b/lms/djangoapps/certificates/tests/test_signals.py index b5993eb623c3..320eec4d61d0 100644 --- a/lms/djangoapps/certificates/tests/test_signals.py +++ b/lms/djangoapps/certificates/tests/test_signals.py @@ -3,12 +3,9 @@ and disabling for instructor-paced courses. """ -from datetime import datetime, timezone from unittest import mock -from uuid import uuid4 import ddt -from django.test.utils import override_settings from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -21,14 +18,10 @@ CertificateGenerationConfiguration, GeneratedCertificate ) -from lms.djangoapps.certificates.signals import listen_for_certificate_created_event from lms.djangoapps.certificates.tests.factories import CertificateAllowlistFactory, GeneratedCertificateFactory from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory from lms.djangoapps.grades.tests.utils import mock_passing_grade from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification -from openedx_events.data import EventsMetadata -from openedx_events.learning.signals import CERTIFICATE_CREATED -from openedx_events.learning.data import CourseData, UserData, UserPersonalData, CertificateData class SelfGeneratedCertsSignalTest(ModuleStoreTestCase): @@ -440,78 +433,3 @@ def test_verified_to_audit(self): ) as mock_allowlist_task: self.verified_enrollment.change_mode('audit') mock_allowlist_task.assert_not_called() - - -class CertificateEventBusTests(ModuleStoreTestCase): - """ - Tests for Certificate events that interact with the event bus. - """ - def setUp(self): - super().setUp() - self.user = UserFactory.create() - self.name = f'{self.user.first_name} {self.user.last_name}' - self.course = CourseFactory.create(self_paced=True) - self.enrollment = CourseEnrollmentFactory( - user=self.user, - course_id=self.course.id, - is_active=True, - mode='verified', - ) - - @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=False) - @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True) - def test_event_disabled(self, mock_producer): - """ - Test to verify that we do not push `CERTIFICATE_CREATED` events to the event bus if the - `SEND_CERTIFICATE_CREATED_SIGNAL` setting is disabled. - """ - listen_for_certificate_created_event(None, CERTIFICATE_CREATED) - mock_producer.assert_not_called() - - @override_settings(SEND_CERTIFICATE_CREATED_SIGNAL=True) - @mock.patch('lms.djangoapps.certificates.signals.get_producer', autospec=True) - def test_event_enabled(self, mock_producer): - """ - Test to verify that we push `CERTIFICATE_CREATED` events to the event bus if the - `SEND_CERTIFICATE_CREATED_SIGNAL` setting is enabled. - """ - expected_course_data = CourseData(course_key=self.course.id) - expected_user_data = UserData( - pii=UserPersonalData( - username=self.user.username, - email=self.user.email, - name=self.name, - ), - id=self.user.id, - is_active=self.user.is_active - ) - expected_certificate_data = CertificateData( - user=expected_user_data, - course=expected_course_data, - mode='verified', - grade='', - current_status='downloadable', - download_url='', - name='', - ) - event_metadata = EventsMetadata( - event_type=CERTIFICATE_CREATED.event_type, - id=uuid4(), - minorversion=0, - source='openedx/lms/web', - sourcehost='lms.test', - time=datetime.now(timezone.utc) - ) - - event_kwargs = { - 'certificate': expected_certificate_data, - 'metadata': event_metadata - } - - listen_for_certificate_created_event(None, CERTIFICATE_CREATED, **event_kwargs) - # verify that the data sent to the event bus matches what we expect - data = mock_producer.return_value.send.call_args.kwargs - assert data['signal'].event_type == CERTIFICATE_CREATED.event_type - assert data['event_data']['certificate'] == expected_certificate_data - assert data['topic'] == 'learning-certificate-lifecycle' - assert data['event_key_field'] == 'certificate.course.course_key' diff --git a/lms/envs/common.py b/lms/envs/common.py index 5cd3a0c06c2d..656ea4717889 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -3274,6 +3274,9 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring # Notifications 'openedx.core.djangoapps.notifications', + + # Openedx events + 'openedx_events', ] ######################### CSRF ######################################### @@ -5334,3 +5337,20 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring ############## NOTIFICATIONS EXPIRY ############## NOTIFICATIONS_EXPIRY = 60 EXPIRED_NOTIFICATIONS_DELETE_BATCH_SIZE = 10000 + +######################## Event bus producer config ######################## + +# .. setting_name: EVENT_BUS_PRODUCER_CONFIG +# .. setting_default: {} +# .. setting_description: Dictionary of event_types mapped to lists of dictionaries containing topic related configuration. +# Each topic configuration dictionary contains +# * a topic/stream name called `topic` where the event will be pushed to. +# * a flag called `enabled` denoting whether the event will be published to the topic. +# * `event_key_field` which is a period-delimited string path to event data field to use as event key. +# Note: The topic names should not include environment prefix as it will be dynamically added based on +# EVENT_BUS_TOPIC_PREFIX setting. +EVENT_BUS_PRODUCER_CONFIG = { + 'org.openedx.learning.certificate.created.v1': [ + {'topic': 'learning-certificate-lifecycle', 'event_key_field': 'certificate.course.course_key', 'enabled': True}, + ], +} diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 67250d9d05ad..c6c1e04d7787 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -762,7 +762,7 @@ openedx-django-require==2.1.0 # via -r requirements/edx/kernel.in openedx-django-wiki==2.0.0 # via -r requirements/edx/kernel.in -openedx-events==8.3.0 +openedx-events @ git+https://github.com/open-craft/openedx-events@navin/configurable-handler # via # -r requirements/edx/kernel.in # edx-event-bus-kafka diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 743938fb1773..1f8068248319 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1294,7 +1294,7 @@ openedx-django-wiki==2.0.0 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt -openedx-events==8.3.0 +openedx-events @ git+https://github.com/open-craft/openedx-events@navin/configurable-handler # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt @@ -2138,6 +2138,7 @@ walrus==0.9.3 # edx-event-bus-redis watchdog==3.0.0 # via + # -r requirements/edx/development.in # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt wcwidth==0.2.6 diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 3b584a4bee5e..4b41bc133483 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -556,7 +556,7 @@ edx-drf-extensions==8.8.0 # edx-rbac # edx-when # edxval -edx-enterprise==4.0.6 +edx-enterprise==4.0.7 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt @@ -905,7 +905,7 @@ openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.0.0 # via -r requirements/edx/base.txt -openedx-events==8.3.0 +openedx-events @ git+https://github.com/open-craft/openedx-events@navin/configurable-handler # via # -r requirements/edx/base.txt # edx-event-bus-kafka diff --git a/requirements/edx/kernel.in b/requirements/edx/kernel.in index 8929520ea819..8cdf504893ac 100644 --- a/requirements/edx/kernel.in +++ b/requirements/edx/kernel.in @@ -113,7 +113,8 @@ oauthlib # OAuth specification support for authentica olxcleaner openedx-calc # Library supporting mathematical calculations for Open edX openedx-django-require -openedx-events>=8.3.0 # Open edX Events from Hooks Extension Framework (OEP-50) +# openedx-events>=8.3.0 # Open edX Events from Hooks Extension Framework (OEP-50) +git+https://github.com/open-craft/openedx-events@navin/configurable-handler openedx-filters # Open edX Filters from Hooks Extension Framework (OEP-50) openedx-learning<=0.1 openedx-mongodbproxy diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 7165c677dc35..e7c4ab1e59b4 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -974,7 +974,7 @@ openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.0.0 # via -r requirements/edx/base.txt -openedx-events==8.3.0 +openedx-events @ git+https://github.com/open-craft/openedx-events@navin/configurable-handler # via # -r requirements/edx/base.txt # edx-event-bus-kafka From b0f157f41e2df5d47f76e124452464d57bd34507 Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Fri, 15 Sep 2023 10:46:24 -0400 Subject: [PATCH 2/7] fixup!: disable events by default --- cms/envs/common.py | 8 ++++---- lms/envs/common.py | 6 +++++- requirements/edx/kernel.in | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cms/envs/common.py b/cms/envs/common.py index e511a9115e0f..cd05e658ea52 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -2742,15 +2742,15 @@ # EVENT_BUS_TOPIC_PREFIX setting. EVENT_BUS_PRODUCER_CONFIG = { 'org.openedx.content_authoring.course.catalog_info.changed.v1': [ - {'topic': 'course-catalog-info-changed', 'event_key_field': 'catalog_info.course_key', 'enabled': True}, + {'topic': 'course-catalog-info-changed', 'event_key_field': 'catalog_info.course_key', 'enabled': False}, ], 'org.openedx.content_authoring.xblock.published.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, ], 'org.openedx.content_authoring.xblock.deleted.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, ], 'org.openedx.content_authoring.xblock.duplicated.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, ], } diff --git a/lms/envs/common.py b/lms/envs/common.py index 656ea4717889..ef0febec49cf 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -5351,6 +5351,10 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring # EVENT_BUS_TOPIC_PREFIX setting. EVENT_BUS_PRODUCER_CONFIG = { 'org.openedx.learning.certificate.created.v1': [ - {'topic': 'learning-certificate-lifecycle', 'event_key_field': 'certificate.course.course_key', 'enabled': True}, + {'topic': 'learning-certificate-lifecycle', 'event_key_field': 'certificate.course.course_key', + 'enabled': False}, ], + 'org.openedx.learning.xblock.skill.verified.v1': [ + {'topic': 'learning-xblock-skill-verified', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + ] } diff --git a/requirements/edx/kernel.in b/requirements/edx/kernel.in index 8cdf504893ac..969ff33eb274 100644 --- a/requirements/edx/kernel.in +++ b/requirements/edx/kernel.in @@ -113,8 +113,8 @@ oauthlib # OAuth specification support for authentica olxcleaner openedx-calc # Library supporting mathematical calculations for Open edX openedx-django-require -# openedx-events>=8.3.0 # Open edX Events from Hooks Extension Framework (OEP-50) -git+https://github.com/open-craft/openedx-events@navin/configurable-handler +# openedx-events 8.3.0 introduces publishing via configuration +openedx-events>=8.3.0 # Open edX Events from Hooks Extension Framework (OEP-50) openedx-filters # Open edX Filters from Hooks Extension Framework (OEP-50) openedx-learning<=0.1 openedx-mongodbproxy From 8f6b6424ae32159e5ad58f2ca20002ac5e722f75 Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Fri, 15 Sep 2023 14:24:42 -0400 Subject: [PATCH 3/7] fixup!: actually bump version --- requirements/constraints.txt | 3 --- requirements/edx/base.txt | 3 +-- requirements/edx/development.txt | 3 +-- requirements/edx/doc.txt | 3 +-- requirements/edx/testing.txt | 3 +-- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 640751aedd8e..b3a09eb01d74 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -123,6 +123,3 @@ libsass==0.10.0 # greater version breaking upgrade builds click==8.1.6 - -# openedx-events 8.6.0 introduces publishing via configuration. Ticket to unpin: https://github.com/edx/edx-arch-experiments/issues/381 -openedx-events<8.6.0 # Open edX Events from Hooks Extension Framework (OEP-50) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 988870298c2c..f4c07b070a52 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -767,9 +767,8 @@ openedx-django-require==2.1.0 # via -r requirements/edx/kernel.in openedx-django-wiki==2.0.1 # via -r requirements/edx/kernel.in -openedx-events==8.5.0 +openedx-events==8.6.0 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/kernel.in # edx-event-bus-kafka # edx-event-bus-redis diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 04b11f026545..4d7fb384c6e1 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1298,9 +1298,8 @@ openedx-django-wiki==2.0.1 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt -openedx-events==8.5.0 +openedx-events==8.6.0 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # edx-event-bus-kafka diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index b2c77926e657..6c8cff1f50ee 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -908,9 +908,8 @@ openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.0.1 # via -r requirements/edx/base.txt -openedx-events==8.5.0 +openedx-events==8.6.0 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # edx-event-bus-kafka # edx-event-bus-redis diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 7e82ccdcb873..55e7210ca5ea 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -978,9 +978,8 @@ openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.0.1 # via -r requirements/edx/base.txt -openedx-events==8.5.0 +openedx-events==8.6.0 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # edx-event-bus-kafka # edx-event-bus-redis From 9c0cf673fe1dd631fd82b337824f37eb8f1e740d Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Mon, 18 Sep 2023 10:15:51 -0400 Subject: [PATCH 4/7] fixup!: rm one more handler --- common/djangoapps/student/handlers.py | 25 ------------------------- lms/envs/common.py | 4 ++++ 2 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 common/djangoapps/student/handlers.py diff --git a/common/djangoapps/student/handlers.py b/common/djangoapps/student/handlers.py deleted file mode 100644 index 6dc841f98fa0..000000000000 --- a/common/djangoapps/student/handlers.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Handlers for student -""" -from django.conf import settings -from django.dispatch import receiver - -from openedx_events.event_bus import get_producer -from openedx_events.learning.signals import ( - COURSE_UNENROLLMENT_COMPLETED, -) - - -@receiver(COURSE_UNENROLLMENT_COMPLETED) -def course_unenrollment_receiver(sender, signal, **kwargs): - """ - Removes user notification preference when user un-enrolls from the course - """ - if settings.FEATURES.get("ENABLE_SEND_ENROLLMENT_EVENTS_OVER_BUS"): - get_producer().send( - signal=COURSE_UNENROLLMENT_COMPLETED, - topic=getattr(settings, "EVENT_BUS_ENROLLMENT_LIFECYCLE_TOPIC", "course-unenrollment-lifecycle"), - event_key_field='enrollment.course.course_key', - event_data={'enrollment': kwargs.get('enrollment')}, - event_metadata=kwargs.get('metadata') - ) diff --git a/lms/envs/common.py b/lms/envs/common.py index 4abf66ddcb46..482b262c470b 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -5400,6 +5400,10 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring ], 'org.openedx.learning.xblock.skill.verified.v1': [ {'topic': 'learning-xblock-skill-verified', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + ], + 'org.openedx.learning.course.unenrollment.completed.v1': [ + {'topic': 'course-unenrollment-lifecycle', 'event_key_field': 'enrollment.course.course_key', + 'enabled': False}, ] } #### django-simple-history## From 2f96f8a9a849dbfaada53ce94901dd15a7531859 Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Mon, 18 Sep 2023 13:55:14 -0400 Subject: [PATCH 5/7] fixup!: annotate better --- cms/envs/common.py | 67 +++++++++++++++++++++++++++++++++++++++++----- lms/envs/common.py | 36 ++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/cms/envs/common.py b/cms/envs/common.py index ae96fd5dc9e3..d065c7ce9d27 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -2777,23 +2777,78 @@ # .. setting_default: {} # .. setting_description: Dictionary of event_types mapped to lists of dictionaries containing topic related configuration. # Each topic configuration dictionary contains -# * a topic/stream name called `topic` where the event will be pushed to. -# * a flag called `enabled` denoting whether the event will be published to the topic. +# * `topic`: the topic where the event will be pushed to. +# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated +# according to +# https://edx.readthedocs.io/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html # * `event_key_field` which is a period-delimited string path to event data field to use as event key. # Note: The topic names should not include environment prefix as it will be dynamically added based on # EVENT_BUS_TOPIC_PREFIX setting. EVENT_BUS_PRODUCER_CONFIG = { 'org.openedx.content_authoring.course.catalog_info.changed.v1': [ - {'topic': 'course-catalog-info-changed', 'event_key_field': 'catalog_info.course_key', 'enabled': False}, + {'topic': 'course-catalog-info-changed', + 'event_key_field': 'catalog_info.course_key', + # .. toggle_name: ENABLE_SEND_COURSE_CATALOG_INFO_CHANGED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: if enabled, will publish COURSE_CATALOG_INFO_CHANGED events to the event bus on the + # course-catalog-info-changed topics + # .. toggle_warning: The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + 'enabled': False}, ], 'org.openedx.content_authoring.xblock.published.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + {'topic': 'content-authoring-xblock-lifecycle', + 'event_key_field': 'xblock_info.usage_key', + # .. toggle_name: ENABLE_SEND_XBLOCK_PUBLISHED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending XBLOCK_PUBLISHED events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: For consistency in user experience, keep the value in sync with the other + # ENABLE_SEND_XBLOCK_* settings in the LMS and CMS. + # The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/31813', + # https://github.com/openedx/openedx-events/issues/210 + 'enabled': False}, ], 'org.openedx.content_authoring.xblock.deleted.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + {'topic': 'content-authoring-xblock-lifecycle', + 'event_key_field': 'xblock_info.usage_key', + # .. toggle_name: ENABLE_SEND_XBLOCK_DELETED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending XBLOCK_DELETED events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: For consistency in user experience, keep the value in sync with the other + # ENABLE_SEND_XBLOCK_* settings in the LMS and CMS. + # The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/31813', + # https://github.com/openedx/openedx-events/issues/210 + 'enabled': False}, ], 'org.openedx.content_authoring.xblock.duplicated.v1': [ - {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + {'topic': 'content-authoring-xblock-lifecycle', + 'event_key_field': 'xblock_info.usage_key', + # .. toggle_name: ENABLE_SEND_XBLOCK_DUPLICATED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending XBLOCK_DUPLICATED events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: For consistency in user experience, keep the value in sync with the other + # ENABLE_SEND_XBLOCK_* settings in the LMS and CMS. + # The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/31813', + # https://github.com/openedx/openedx-events/issues/210 + 'enabled': False}, ], } #### django-simple-history## diff --git a/lms/envs/common.py b/lms/envs/common.py index 482b262c470b..e9eb40242155 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -5388,21 +5388,51 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring # .. setting_default: {} # .. setting_description: Dictionary of event_types mapped to lists of dictionaries containing topic related configuration. # Each topic configuration dictionary contains -# * a topic/stream name called `topic` where the event will be pushed to. -# * a flag called `enabled` denoting whether the event will be published to the topic. +# * `topic`: the topic where the event will be pushed to. +# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated +# according to +# https://edx.readthedocs.io/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html # * `event_key_field` which is a period-delimited string path to event data field to use as event key. # Note: The topic names should not include environment prefix as it will be dynamically added based on # EVENT_BUS_TOPIC_PREFIX setting. EVENT_BUS_PRODUCER_CONFIG = { 'org.openedx.learning.certificate.created.v1': [ {'topic': 'learning-certificate-lifecycle', 'event_key_field': 'certificate.course.course_key', + # .. toggle_name: ENABLE_SEND_LEARNING_CERTIFICATE_CREATED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending learning-certificate-created events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: https://github.com/openedx/openedx-events/issues/210 'enabled': False}, ], 'org.openedx.learning.xblock.skill.verified.v1': [ - {'topic': 'learning-xblock-skill-verified', 'event_key_field': 'xblock_info.usage_key', 'enabled': False}, + {'topic': 'learning-xblock-skill-verified', 'event_key_field': 'xblock_info.usage_key', + # .. toggle_name: ENABLE_SEND_XBLOCK_SKILL_VERIFIED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending xblock_skill_verified events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: https://github.com/openedx/openedx-events/issues/210 + 'enabled': False}, ], 'org.openedx.learning.course.unenrollment.completed.v1': [ {'topic': 'course-unenrollment-lifecycle', 'event_key_field': 'enrollment.course.course_key', + # .. toggle_name: ENABLE_SEND_COURSE_UNENROLLMENT_COMPLETED_EVENTS_OVER_BUS + # .. toggle_implementation: DjangoSetting + # .. toggle_default: False + # .. toggle_description: Enables sending COURSE_UNENROLLMENT_COMPLETED events over the event bus. + # .. toggle_use_cases: opt_in + # .. toggle_creation_date: 2023-09-18 + # .. toggle_warning: The default may be changed in a later release. See + # https://github.com/openedx/openedx-events/issues/265 + # .. toggle_tickets: https://github.com/openedx/openedx-events/issues/210 'enabled': False}, ] } From 982b224b30e62bf99e0c0107d87af55a8242c128 Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Mon, 18 Sep 2023 13:56:51 -0400 Subject: [PATCH 6/7] fixup!: rm old handler tests --- .../djangoapps/student/tests/test_handlers.py | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 common/djangoapps/student/tests/test_handlers.py diff --git a/common/djangoapps/student/tests/test_handlers.py b/common/djangoapps/student/tests/test_handlers.py deleted file mode 100644 index bd8d6a9baf47..000000000000 --- a/common/djangoapps/student/tests/test_handlers.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Unit tests for event bus tests for course unenrollments -""" - -import unittest -from datetime import datetime, timezone -from unittest import mock -from uuid import uuid4 - -from django.test.utils import override_settings -from common.djangoapps.student.handlers import course_unenrollment_receiver -from common.djangoapps.student.tests.factories import ( - UserFactory, - CourseEnrollmentFactory, -) - -from openedx_events.data import EventsMetadata -from openedx_events.learning.signals import COURSE_UNENROLLMENT_COMPLETED -from pytest import mark - - -@mark.django_db -class UnenrollmentEventBusTests(unittest.TestCase): - """ - Tests for unenrollment events that interact with the event bus. - """ - @override_settings(ENABLE_SEND_ENROLLMENT_EVENTS_OVER_BUS=False) - @mock.patch('common.djangoapps.student.handlers.get_producer', autospec=True) - def test_event_disabled(self, mock_producer): - """ - Test to verify that we do not push `CERTIFICATE_CREATED` events to the event bus if the - `SEND_CERTIFICATE_CREATED_SIGNAL` setting is disabled. - """ - course_unenrollment_receiver(None, None) - mock_producer.assert_not_called() - - @override_settings(FEATURES={'ENABLE_SEND_ENROLLMENT_EVENTS_OVER_BUS': True}) - @mock.patch('common.djangoapps.student.handlers.get_producer', autospec=True) - def test_event_enabled(self, mock_producer): - """ - Test to verify that we push `COURSE_UNENROLLMENT_COMPLETED` events to the event bus. - """ - user = UserFactory() - enrollment = CourseEnrollmentFactory(user=user) - - event_metadata = EventsMetadata( - event_type=COURSE_UNENROLLMENT_COMPLETED.event_type, - id=uuid4(), - minorversion=0, - source='openedx/lms/web', - sourcehost='lms.test', - time=datetime.now(timezone.utc) - ) - - event_kwargs = { - 'enrollment': enrollment, - 'metadata': event_metadata - } - course_unenrollment_receiver(None, COURSE_UNENROLLMENT_COMPLETED, **event_kwargs) - - # verify that the data sent to the event bus matches what we expect - print(mock_producer.return_value) - print(mock_producer.return_value.send.call_args) - data = mock_producer.return_value.send.call_args.kwargs - assert data['event_data']['enrollment'] == enrollment - assert data['topic'] == 'course-unenrollment-lifecycle' - assert data['event_key_field'] == 'enrollment.course.course_key' From bf8224f242475a0305be231c3b252b1acef0138b Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Mon, 18 Sep 2023 15:23:32 -0400 Subject: [PATCH 7/7] fixup!: delete more --- lms/djangoapps/certificates/config.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lms/djangoapps/certificates/config.py b/lms/djangoapps/certificates/config.py index fa9b3f2f824e..10caa1338921 100644 --- a/lms/djangoapps/certificates/config.py +++ b/lms/djangoapps/certificates/config.py @@ -15,16 +15,3 @@ # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2017-09-14 AUTO_CERTIFICATE_GENERATION = WaffleSwitch(f"{WAFFLE_NAMESPACE}.auto_certificate_generation", __name__) - - -# .. toggle_name: SEND_CERTIFICATE_CREATED_SIGNAL -# .. toggle_implementation: SettingToggle -# .. toggle_default: False -# .. toggle_description: When True, the system will publish `CERTIFICATE_CREATED` signals to the event bus. The -# `CERTIFICATE_CREATED` signal is emit when a certificate has been awarded to a learner and the creation process has -# completed. -# .. toggle_use_cases: temporary -# .. toggle_creation_date: 2023-04-11 -# .. toggle_target_removal_date: 2023-07-31 -# .. toggle_tickets: TODO -SEND_CERTIFICATE_CREATED_SIGNAL = SettingToggle('SEND_CERTIFICATE_CREATED_SIGNAL', default=False, module_name=__name__)