Merge pull request #30466 from openedx/ammar/send-segment-event-for-first-time-passed-learners

feat: send segment event for learners who passed a course first time
This commit is contained in:
Muhammad Ammar
2022-05-27 17:30:23 +05:00
committed by GitHub
4 changed files with 102 additions and 13 deletions

View File

@@ -1,19 +1,25 @@
"""
Emits course grade events.
"""
from logging import getLogger
from crum import get_current_user
from eventtracking import tracker
from common.djangoapps.track import contexts
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.track import contexts, segment
from common.djangoapps.track.event_transaction_utils import (
create_new_event_transaction_id,
get_event_transaction_id,
get_event_transaction_type,
set_event_transaction_type
)
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.features.enterprise_support.context import get_enterprise_event_context
log = getLogger(__name__)
COURSE_GRADE_CALCULATED = 'edx.grades.course.grade_calculated'
GRADES_OVERRIDE_EVENT_TYPE = 'edx.grades.problem.score_overridden'
GRADES_RESCORE_EVENT_TYPE = 'edx.grades.problem.rescored'
@@ -24,6 +30,7 @@ SUBSECTION_GRADE_CALCULATED = 'edx.grades.subsection.grade_calculated'
COURSE_GRADE_PASSED_FIRST_TIME_EVENT_TYPE = 'edx.course.grade.passed.first_time'
COURSE_GRADE_NOW_PASSED_EVENT_TYPE = 'edx.course.grade.now_passed'
COURSE_GRADE_NOW_FAILED_EVENT_TYPE = 'edx.course.grade.now_failed'
LEARNER_PASSED_COURSE_FIRST_TIME = 'edx.course.learner.passed.first_time'
def grade_updated(**kwargs):
@@ -200,3 +207,42 @@ def course_grade_now_failed(user, course_id):
'event_transaction_type': str(get_event_transaction_type())
}
)
def fire_segment_event_on_course_grade_passed_first_time(user_id, course_locator):
"""
Fire a segment event `edx.course.grade.passed.first_time` with the desired data.
* Event should be only fired for learners enrolled in paid enrollment modes.
"""
event_name = LEARNER_PASSED_COURSE_FIRST_TIME
courserun_key = str(course_locator)
courserun_org = course_locator.org
paid_enrollment_modes = (
CourseMode.MASTERS,
CourseMode.VERIFIED,
CourseMode.CREDIT_MODE,
CourseMode.PROFESSIONAL,
CourseMode.NO_ID_PROFESSIONAL_MODE,
)
try:
__ = CourseEnrollment.objects.get(user_id=user_id, course_id=courserun_key, mode__in=paid_enrollment_modes)
except CourseEnrollment.DoesNotExist:
return
try:
courserun_display_name = CourseOverview.objects.values_list('display_name', flat=True).get(id=courserun_key)
except CourseOverview.DoesNotExist:
return
event_properties = {
'LMS_USER_ID': user_id,
'COURSERUN_KEY': courserun_key,
'COURSE_TITLE': courserun_display_name,
'COURSE_ORG_NAME': courserun_org,
'PASSED': 1,
}
segment.track(user_id, event_name, event_properties)
log.info("Segment event fired for passed learners. Event: [{}], Data: [{}]".format(event_name, event_properties))

View File

@@ -299,3 +299,4 @@ def listen_for_course_grade_passed_first_time(sender, user_id, course_id, **kwar
Emits an event edx.course.grade.passed.first_time
"""
events.course_grade_passed_first_time(user_id, course_id)
events.fire_segment_event_on_course_grade_passed_first_time(user_id, course_id)

View File

@@ -130,7 +130,7 @@ class TestCourseGradeFactory(GradeTestBase):
with self.assertNumQueries(4), mock_get_score(1, 2):
_assert_read(expected_pass=False, expected_percent=0) # start off with grade of 0
num_queries = 41
num_queries = 42
with self.assertNumQueries(num_queries), mock_get_score(1, 2):
grade_factory.update(self.request.user, self.course, force_update_subsections=True)

View File

@@ -11,21 +11,25 @@ import ddt
import pytest
import pytz
from django.test import TestCase
from submissions.models import score_reset, score_set
from opaque_keys.edx.locator import CourseLocator
from submissions.models import score_reset, score_set
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.track.event_transaction_utils import get_event_transaction_id, get_event_transaction_type
from common.djangoapps.util.date_utils import to_timestamp
from lms.djangoapps.grades.models import PersistentCourseGrade
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from ..constants import ScoreDatabaseTableEnum
from ..signals.handlers import (
disconnect_submissions_signal_receiver,
listen_for_course_grade_passed_first_time,
listen_for_failing_grade,
listen_for_passing_grade,
problem_raw_score_changed_handler,
submissions_score_reset_handler,
submissions_score_set_handler,
listen_for_course_grade_passed_first_time,
listen_for_passing_grade,
listen_for_failing_grade
submissions_score_set_handler
)
from ..signals.signals import PROBLEM_RAW_SCORE_CHANGED
@@ -266,7 +270,7 @@ class ScoreChangedSignalRelayTest(TestCase):
pass
class CourseEventsSignalsTest(TestCase):
class CourseEventsSignalsTest(ModuleStoreTestCase):
"""
Tests to ensure that the courseware module correctly catches
course grades passed/failed signal and emit course related event
@@ -281,10 +285,6 @@ class CourseEventsSignalsTest(TestCase):
Configure mocks for all the dependencies of the render method
"""
super().setUp()
self.signal_mock = self.setup_patch(
'lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_FIRST_TIME.send',
None,
)
self.user_mock = MagicMock()
self.user_mock.id = 42
self.get_user_mock = self.setup_patch(
@@ -296,6 +296,8 @@ class CourseEventsSignalsTest(TestCase):
course='some_course',
run='some_run'
)
self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx")
self.client.login(username=self.user.username, password="edx")
def setup_patch(self, function_name, return_value):
"""
@@ -385,3 +387,43 @@ class CourseEventsSignalsTest(TestCase):
'event_transaction_type': str(get_event_transaction_type()),
}
)
@patch('lms.djangoapps.grades.events.segment.track')
def test_segment_event_on_course_grade_passed_first_time(self, segment_track_mock):
course = CourseOverviewFactory()
__ = CourseEnrollmentFactory(
is_active=True,
mode='verified',
course=course,
user=self.user
)
params = {
"user_id": self.user.id,
"course_id": course.id,
"course_version": "JoeMcEwing",
"course_edited_timestamp": datetime(
year=2016,
month=8,
day=1,
hour=18,
minute=53,
second=24,
microsecond=354741,
tzinfo=pytz.UTC,
),
"percent_grade": 77.7,
"letter_grade": "Great job",
"passed": True,
}
__ = PersistentCourseGrade.update_or_create(**params)
segment_track_mock.assert_called_with(
self.user.id,
'edx.course.learner.passed.first_time',
{
'LMS_USER_ID': self.user.id,
'COURSERUN_KEY': str(course.id),
'COURSE_TITLE': course.display_name,
'COURSE_ORG_NAME': course.org,
'PASSED': 1,
}
)