Skip to content
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

feat: adding unenrollments to event bus #33085

Merged
merged 6 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cms/envs/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,13 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
# in the LMS and CMS.
# .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/31813'
FEATURES['ENABLE_SEND_XBLOCK_EVENTS_OVER_BUS'] = True
FEATURES['ENABLE_SEND_ENROLLMENT_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'
EVENT_BUS_ENROLLMENT_LIFECYCLE_TOPIC = 'course-authoring-enrollment-lifecycle'

################# New settings must go ABOVE this line #################
########################################################################
Expand Down
25 changes: 25 additions & 0 deletions common/djangoapps/student/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
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')
)
67 changes: 67 additions & 0 deletions common/djangoapps/student/tests/test_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
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'
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/notifications/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def on_user_course_unenrollment(enrollment, **kwargs):
preference = CourseNotificationPreference.objects.get(user__id=user_id, course_id=course_key)
preference.delete()
except ObjectDoesNotExist:
log.info(f'Notification Preference doesnot exist for {enrollment.user.pii.username} in {course_key}')
log.info(f'Notification Preference does not exist for {enrollment.user.pii.username} in {course_key}')


@receiver(USER_NOTIFICATION_REQUESTED)
Expand Down