Call segment.identify with any changed values when user profile fields change

This commit is contained in:
Calen Pennington
2021-01-12 11:27:53 -05:00
parent e858addce1
commit fdac36ec13
4 changed files with 86 additions and 5 deletions

View File

@@ -2,6 +2,7 @@
Utilities for django models.
"""
from typing import Dict, Any, Tuple
import six
from django.conf import settings
@@ -13,6 +14,7 @@ from eventtracking import tracker
USER_SETTINGS_CHANGED_EVENT_NAME = u'edx.user.settings.changed'
# Used to signal a field value change
USER_FIELD_CHANGED = Signal(providing_args=["user", "table", "setting", "old_value", "new_value"])
USER_FIELDS_CHANGED = Signal(providing_args=["user", "table", "changed_values"])
def get_changed_fields_dict(instance, model_class):
@@ -88,11 +90,14 @@ def emit_field_changed_events(instance, user, db_table, excluded_fields=None, hi
excluded_fields = excluded_fields or []
hidden_fields = hidden_fields or []
changed_fields = getattr(instance, '_changed_fields', {})
clean_changed_fields = {}
for field_name in changed_fields:
if field_name not in excluded_fields:
old_value = clean_field(field_name, changed_fields[field_name])
new_value = clean_field(field_name, getattr(instance, field_name))
clean_changed_fields[field_name] = (old_value, new_value)
emit_setting_changed_event(user, db_table, field_name, old_value, new_value)
emit_settings_changed_event(user, db_table, clean_changed_fields)
# Remove the now inaccurate _changed_fields attribute.
if hasattr(instance, '_changed_fields'):
del instance._changed_fields
@@ -156,6 +161,21 @@ def emit_setting_changed_event(user, db_table, setting_name, old_value, new_valu
old_value=old_value, new_value=new_value)
def emit_settings_changed_event(user, db_table, changed_fields: Dict[str, Tuple[Any, Any]]):
"""Emits an event for a change in a setting.
Args:
user (User): the user that this setting is associated with.
db_table (str): the name of the table that we're modifying.
changed_fields: all changed settings, with both their old and new values
Returns:
None
"""
# Announce field change
USER_FIELDS_CHANGED.send(sender=None, user=user, table=db_table, changed_fields=changed_fields)
def _get_truncated_setting_value(value, max_length=None):
"""
Returns the truncated form of a setting value.

View File

@@ -6,9 +6,10 @@ This module contains signals needed for email integration
import datetime
import logging
from random import randint
from typing import Dict, Any, Optional, Tuple
import crum
from celery.exceptions import TimeoutError
from celery.exceptions import TimeoutError as CeleryTimeoutError
from django.conf import settings
from django.dispatch import receiver
from sailthru.sailthru_error import SailthruClientError
@@ -28,7 +29,9 @@ from openedx.core.djangoapps.user_authn.cookies import CREATE_LOGON_COOKIE
from openedx.core.djangoapps.user_authn.views.register import REGISTER_USER
from common.djangoapps.student.helpers import does_user_profile_exist
from common.djangoapps.student.signals import SAILTHRU_AUDIT_PURCHASE
from common.djangoapps.util.model_utils import USER_FIELD_CHANGED
from common.djangoapps.student.models import UserProfile
from common.djangoapps.track import segment
from common.djangoapps.util.model_utils import USER_FIELD_CHANGED, USER_FIELDS_CHANGED
from .models import EmailMarketingConfiguration
@@ -101,7 +104,7 @@ def add_email_marketing_cookies(sender, response=None, user=None,
cookie = sailthru_response.result
_log_sailthru_api_call_time(time_before_call)
except TimeoutError as exc:
except CeleryTimeoutError as exc:
log.error(u"Timeout error while attempting to obtain cookie from Sailthru: %s", text_type(exc))
return response
except SailthruClientError as exc:
@@ -221,6 +224,45 @@ def email_marketing_user_field_changed(sender, user=None, table=None, setting=No
update_user_email.delay(user.email, old_value)
@receiver(USER_FIELDS_CHANGED)
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
)
def _create_sailthru_user_vars(user, profile, registration=None):
"""
Create sailthru user create/update vars from user + profile.

View File

@@ -23,7 +23,7 @@ from common.djangoapps.student.models import (
email_exists_or_retired,
username_exists_or_retired
)
from common.djangoapps.util.model_utils import emit_setting_changed_event
from common.djangoapps.util.model_utils import emit_setting_changed_event, emit_settings_changed_event
from common.djangoapps.util.password_policy_validators import validate_password
from openedx.core.djangoapps.user_api import accounts, errors, helpers
@@ -277,6 +277,11 @@ def _notify_language_proficiencies_update_if_needed(data, user, user_profile, ol
old_value=old_language_proficiencies,
new_value=new_language_proficiencies,
)
emit_settings_changed_event(
user=user,
db_table=user_profile.language_proficiencies.model._meta.db_table,
changed_fields={"language_proficiencies": (old_language_proficiencies, new_language_proficiencies)},
)
def _update_extended_profile_if_needed(data, user_profile):

View File

@@ -29,7 +29,11 @@ from common.djangoapps.student.models import (
get_retired_email_by_email,
get_retired_username_by_username
)
from common.djangoapps.util.model_utils import emit_setting_changed_event, get_changed_fields_dict
from common.djangoapps.util.model_utils import (
emit_setting_changed_event,
get_changed_fields_dict,
emit_settings_changed_event,
)
class RetirementStateError(Exception):
@@ -122,6 +126,11 @@ def post_save_callback(sender, **kwargs):
user_preference.user, sender._meta.db_table, user_preference.key,
user_preference._old_value, user_preference.value # pylint: disable=protected-access
)
emit_settings_changed_event(
user_preference.user,
sender._meta.db_table,
{user_preference.key: (user_preference._old_value, user_preference.value)} # pylint: disable=protected-access
)
user_preference._old_value = None # pylint: disable=protected-access
@@ -134,6 +143,11 @@ def post_delete_callback(sender, **kwargs):
emit_setting_changed_event(
user_preference.user, sender._meta.db_table, user_preference.key, user_preference.value, None
)
emit_settings_changed_event(
user_preference.user,
sender._meta.db_table,
{user_preference.key: (user_preference.value, None)}
)
class UserCourseTag(models.Model):