Skip to content

Commit

Permalink
feat: adding unenrollments to event bus (#33085)
Browse files Browse the repository at this point in the history
* feat: adding unenrollments to event bus

* fix: quality fixes

* fix: tweaks to pass tests

* fix: more tweaks for testing

---------

Co-authored-by: John Nagro <jnagro@edx.org>
  • Loading branch information
kiram15 and johnnagro authored Aug 28, 2023
1 parent 2f8475c commit 776f4bf
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
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

0 comments on commit 776f4bf

Please sign in to comment.