Esempio n. 1
0
 def test_call_with_context(self):
     provided_context = {sentinel.context_key: sentinel.context_value}
     segment.identify(sentinel.user_id, self.properties, provided_context)
     self.assertTrue(self.mock_segment_identify.called)
     args, kwargs = self.mock_segment_identify.call_args  # lint-amnesty, pylint: disable=unused-variable
     self.assertEqual((sentinel.user_id, self.properties, provided_context),
                      args)
Esempio n. 2
0
def _track_user_login(user, request):
    """
    Sends a tracking event for a successful login.
    """
    # .. pii: Username and email are sent to Segment here. Retired directly through Segment API call in Tubular.
    # .. pii_types: email_address, username
    # .. pii_retirement: third_party
    segment.identify(
        user.id,
        {
            'email': request.POST.get('email'),
            'username': user.username
        },
        {
            # Disable MailChimp because we don't want to update the user's email
            # and username in MailChimp on every page load. We only need to capture
            # this data on registration/activation.
            'MailChimp': False
        })
    segment.track(
        user.id,
        "edx.bi.user.account.authenticated",
        {
            'category': "conversion",
            'label': request.POST.get('course_id'),
            'provider': None
        },
    )
Esempio n. 3
0
 def test_call_with_context(self):
     provided_context = {sentinel.context_key: sentinel.context_value}
     segment.identify(sentinel.user_id, self.properties, provided_context)
     self.assertTrue(self.mock_segment_identify.called)
     args, kwargs = self.mock_segment_identify.call_args
     self.assertEqual((sentinel.user_id, self.properties, provided_context),
                      args)
Esempio n. 4
0
def user_fields_changed(
    user=None,
    table=None,
    changed_fields: Optional[Dict[str, Tuple[Any, Any]]] = None,
    **_kwargs,
):
    """
    Update a collection of user profile fields in segment when they change in the database

    Args:
        user: The user object for the user being changed
        table: The name of the table being updated
        changed_fields: A mapping from changed field name to old and new values.
    """

    fields = {
        field: new_value
        for (field, (old_value, new_value)) in changed_fields.items()
    }
    # This mirrors the logic in ./views/register.py:_track_user_registration
    if table == 'auth_userprofile':
        if 'gender' in fields and fields['gender']:
            fields['gender'] = dict(
                UserProfile.GENDER_CHOICES)[fields['gender']]
        if 'country' in fields:
            fields['country'] = str(fields['country'])
        if 'level_of_education' in fields and fields['level_of_education']:
            fields['education'] = dict(UserProfile.LEVEL_OF_EDUCATION_CHOICES)[
                fields['level_of_education']]
        if 'year_of_birth' in fields:
            fields['yearOfBirth'] = fields.pop('year_of_birth')
        if 'mailing_address' in fields:
            fields['address'] = fields.pop('mailing_address')

    segment.identify(user.id, fields)
Esempio n. 5
0
def _track_user_registration(user, profile, params, third_party_provider):
    """ Track the user's registration. """
    if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        identity_args = [
            user.id,
            {
                'email': user.email,
                'username': user.username,
                'name': profile.name,
                # Mailchimp requires the age & yearOfBirth to be integers, we send a sane integer default if falsey.
                'age': profile.age or -1,
                'yearOfBirth': profile.year_of_birth or datetime.datetime.now(UTC).year,
                'education': profile.level_of_education_display,
                'address': profile.mailing_address,
                'gender': profile.gender_display,
                'country': text_type(profile.country),
            }
        ]
        # .. pii: Many pieces of PII are sent to Segment here. Retired directly through Segment API call in Tubular.
        # .. pii_types: email_address, username, name, birth_date, location, gender
        # .. pii_retirement: third_party
        segment.identify(*identity_args)
        segment.track(
            user.id,
            "edx.bi.user.account.registered",
            {
                'category': 'conversion',
                # ..pii: Learner email is sent to Segment in following line and will be associated with analytics data.
                'email': user.email,
                'label': params.get('course_id'),
                'provider': third_party_provider.name if third_party_provider else None
            },
        )
Esempio n. 6
0
def emit_event_for_bu_courses_progress(user, status):
    """
    Emit event to update the progress of Business Unit courses

    Arguments:
        user (User): User for which to emit the BU courses progress update
        status (str): Progress of the bu courses
    """
    segment.identify(user.id, {'businessLineCoursesStatus': status})
Esempio n. 7
0
def _track_user_registration(user, profile, params, third_party_provider, registration):
    """ Track the user's registration. """
    if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY:
        identity_args = [
            user.id,
            {
                'email': user.email,
                'username': user.username,
                'name': profile.name,
                # Mailchimp requires the age & yearOfBirth to be integers, we send a sane integer default if falsey.
                'age': profile.age or -1,
                'yearOfBirth': profile.year_of_birth or datetime.datetime.now(UTC).year,
                'education': profile.level_of_education_display,
                'address': profile.mailing_address,
                'gender': profile.gender_display,
                'country': str(profile.country),
                'email_subscribe': 'unsubscribed' if settings.MARKETING_EMAILS_OPT_IN and
                                   params.get('marketing_emails_opt_in') == 'false' else 'subscribed',
            }
        ]
        # .. pii: Many pieces of PII are sent to Segment here. Retired directly through Segment API call in Tubular.
        # .. pii_types: email_address, username, name, birth_date, location, gender
        # .. pii_retirement: third_party
        segment.identify(*identity_args)
        properties = {
            'category': 'conversion',
            # ..pii: Learner email is sent to Segment in following line and will be associated with analytics data.
            'email': user.email,
            'label': params.get('course_id'),
            'provider': third_party_provider.name if third_party_provider else None,
            'is_gender_selected': bool(profile.gender_display),
            'is_year_of_birth_selected': bool(profile.year_of_birth),
            'is_education_selected': bool(profile.level_of_education_display),
            'is_goal_set': bool(profile.goals),
            'total_registration_time': round(float(params.get('totalRegistrationTime', '0'))),
            'activation_key': registration.activation_key if registration else None,
        }
        # VAN-738 - added below properties to experiment marketing emails opt in/out events on Braze.
        if params.get('marketing_emails_opt_in') and settings.MARKETING_EMAILS_OPT_IN:
            properties['marketing_emails_opt_in'] = params.get('marketing_emails_opt_in') == 'true'

        # DENG-803: For segment events forwarded along to Hubspot, duplicate the `properties` section of
        # the event payload into the `traits` section so that they can be received. This is a temporary
        # fix until we implement this behavior outside of the LMS.
        # TODO: DENG-805: remove the properties duplication in the event traits.
        segment_traits = dict(properties)
        segment_traits['user_id'] = user.id
        segment_traits['joined_date'] = user.date_joined.strftime("%Y-%m-%d")
        segment.track(
            user.id,
            "edx.bi.user.account.registered",
            properties=properties,
            traits=segment_traits,
        )
Esempio n. 8
0
def emit_registration_event(user):
    """
    Track and Identify required attributes when a new user is created

    Arguments:
        user (User): User to track
    """
    user_properties = {
        'email': user.email,
        'username': user.username,
        'name': user.profile.name,
        'city': user.profile.city,
    }
    segment.identify(user.id, user_properties)
    segment.track(user.id, USER_REGISTRATION_EVENT, user_properties)
Esempio n. 9
0
def emit_course_status_event_for_program_prereq_courses(user_id, course, course_status):
    """
    Emit the progress status for Program prereq courses i.e Started or Completed

    Arguments:
        user_id (id): Id of the user for which to emit the Omni course progress update
        course (CourseOverview): Course for which to emit the event for
        course_status (str): The status of the given course
    """
    course_name_status_key = f'{course.id.course}Status'
    segment.identify(user_id, {course_name_status_key: course_status})

    course_update_event_name = f'ProgramPrereq{course_status}'
    segment.track(user_id, course_update_event_name, {
        'course': course.id.course,
        'label': text_type(course.id),
        'org': course.id.org,
        'run': course.id.run,
    })
Esempio n. 10
0
def emit_user_info_update(user, application_step):
    """
    Emit an event to update the user information at Segment after different steps of the application.

    Arguments:
        user (User): User for which to emit the event
        application_step (str): Step of the application to update the user information for
    """
    if application_step == CONTACT_INFO:
        attributes = {
            'isSaudi': user.extended_profile.saudi_national,
            'age': user.extended_profile.age,
            'heardAboutUs': user.extended_profile.hear_about_omni,
        }

    elif application_step == EXPERIENCE:
        first_education = user.application.educations.first()
        education_start_date, education_end_date = _get_start_date_and_end_date(first_education)
        attributes = {
            'school': first_education.name_of_school,
            'degree': first_education.get_degree_display(),
            'educationStartDate': education_start_date,
            'educationEndDate': education_end_date,
        }

        first_experience = user.application.workexperiences.first()
        if first_experience:
            experience_start_date, experience_end_date = _get_start_date_and_end_date(first_experience)
            attributes.update({
                'workOrganization': first_experience.name_of_organization,
                'jobTitle': first_experience.job_position_title,
                'workStartDate': experience_start_date,
                'workEndDate': experience_end_date
            })

    else:
        attributes = {
            'businessLine': user.application.business_line.title
        }

    segment.identify(user.id, attributes)
    segment.track(user.id, APPLICATION_EVENTS.get(application_step), attributes)
Esempio n. 11
0
def emit_application_progress(user):
    """
    Emit the progress for the application of the given user. The progress statuses can be Started, Submitted,
    Waitlisted and Accepted.

    Arguments:
        user (User): User to emit progress update for
    """
    application_progress = user.application_hub.application_progress

    application_status = APPLICATION_PROGRESS.get(application_progress, APPLICATION_PROGRESS[APPLICATION_STARTED])
    segment.identify(user.id, {'applicationStatus': application_status})

    application_event = APPLICATION_EVENTS.get(application_progress, APPLICATION_EVENTS[APPLICATION_STARTED])
    event_properties = {
        'applicationStatus': application_status
    }
    if hasattr(user, 'application'):
        event_properties['applicationId'] = user.application.id
    segment.track(user.id, application_event, event_properties)
Esempio n. 12
0
def email_marketing_user_fields_changed(
        sender,  # pylint: disable=unused-argument
        user=None,
        table=None,
        changed_fields: Optional[Dict[str, Tuple[Any, Any]]] = None,
        **kwargs):
    """
    Update a collection of user profile fields

    Args:
        sender: Not used
        user: The user object for the user being changed
        table: The name of the table being updated
        changed_fields: A mapping from changed field name to old and new values.
        kwargs: Not used
    """

    fields = {
        field: new_value
        for (field, (old_value, new_value)) in changed_fields.items()
    }
    # This mirrors the logic in openedx/core/djangoapps/user_authn/views/register.py:_track_user_registration
    if table == 'auth_userprofile':
        if 'gender' in fields and fields['gender']:
            fields['gender'] = dict(
                UserProfile.GENDER_CHOICES)[fields['gender']]
        if 'country' in fields:
            fields['country'] = str(fields['country'])
        if 'level_of_education' in fields and fields['level_of_education']:
            fields['level_of_education'] = dict(
                UserProfile.LEVEL_OF_EDUCATION_CHOICES)[
                    fields['level_of_education']]
        if 'year_of_birth' in fields:
            fields['yearOfBirth'] = fields.pop('year_of_birth')
        if 'mailing_address' in fields:
            fields['address'] = fields.pop('mailing_address')

    segment.identify(user.id, fields)
Esempio n. 13
0
 def test_normal_call(self):
     segment.identify(sentinel.user_id, self.properties)
     assert self.mock_segment_identify.called
     args, kwargs = self.mock_segment_identify.call_args  # lint-amnesty, pylint: disable=unused-variable
     assert (sentinel.user_id, self.properties, {}) == args
Esempio n. 14
0
 def test_null_key(self):
     segment.identify(sentinel.user_id, self.properties)
     assert not self.mock_segment_identify.called
Esempio n. 15
0
 def test_normal_call(self):
     segment.identify(sentinel.user_id, self.properties)
     self.assertTrue(self.mock_segment_identify.called)
     args, kwargs = self.mock_segment_identify.call_args  # lint-amnesty, pylint: disable=unused-variable
     self.assertEqual((sentinel.user_id, self.properties, {}), args)
Esempio n. 16
0
 def test_missing_key(self):
     segment.identify(sentinel.user_id, self.properties)
     self.assertFalse(self.mock_segment_identify.called)
Esempio n. 17
0
 def test_normal_call(self):
     segment.identify(sentinel.user_id, self.properties)
     self.assertTrue(self.mock_segment_identify.called)
     args, kwargs = self.mock_segment_identify.call_args
     self.assertEqual((sentinel.user_id, self.properties, {}), args)