Pwattenberger/sailthru (#12646)
* Initial commit of Sailthru lms changes * Field mapping changes for Sailthru integration * Merge fix * Add users to Sailthru list on registration * FIx minor code format issues * Several updates based on code review feedback * Updates based on recomendations from Sailthru * Clean up unit tests * Fix last login * Updates based on code review feedback * Updates based on code review feedback * Fix comment * Cleanup
This commit is contained in:
@@ -5,10 +5,14 @@ Utility functions for setting "logged in" cookies used by subdomains.
|
||||
import time
|
||||
import json
|
||||
|
||||
from django.dispatch import Signal
|
||||
|
||||
from django.utils.http import cookie_date
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||
|
||||
CREATE_LOGON_COOKIE = Signal(providing_args=["user", "response"])
|
||||
|
||||
|
||||
def set_logged_in_cookies(request, response, user):
|
||||
"""
|
||||
@@ -118,6 +122,9 @@ def set_logged_in_cookies(request, response, user):
|
||||
**cookie_settings
|
||||
)
|
||||
|
||||
# give signal receivers a chance to add cookies
|
||||
CREATE_LOGON_COOKIE.send(sender=None, user=user, response=response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ from django.utils.translation import ugettext as _, get_language
|
||||
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_POST, require_GET
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.dispatch import receiver, Signal
|
||||
from django.template.response import TemplateResponse
|
||||
|
||||
from ratelimitbackend.exceptions import RateLimitException
|
||||
@@ -135,6 +135,8 @@ ReverifyInfo = namedtuple('ReverifyInfo', 'course_id course_name course_number d
|
||||
SETTING_CHANGE_INITIATED = 'edx.user.settings.change_initiated'
|
||||
# Used as the name of the user attribute for tracking affiliate registrations
|
||||
REGISTRATION_AFFILIATE_ID = 'registration_affiliate_id'
|
||||
# used to announce a registration
|
||||
REGISTER_USER = Signal(providing_args=["user", "profile"])
|
||||
|
||||
# Disable this warning because it doesn't make sense to completely refactor tests to appease Pylint
|
||||
# pylint: disable=logging-format-interpolation
|
||||
@@ -1754,6 +1756,9 @@ def create_account_with_params(request, params):
|
||||
}
|
||||
)
|
||||
|
||||
# Announce registration
|
||||
REGISTER_USER.send(sender=None, user=user, profile=profile)
|
||||
|
||||
create_comments_service_user(user)
|
||||
|
||||
# Don't send email if we are:
|
||||
|
||||
@@ -9,11 +9,14 @@ from eventtracking import tracker
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.dispatch import Signal
|
||||
|
||||
from django_countries.fields import Country
|
||||
|
||||
# The setting name used for events when "settings" (account settings, preferences, profile information) change.
|
||||
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"])
|
||||
|
||||
|
||||
def get_changed_fields_dict(instance, model_class):
|
||||
@@ -152,6 +155,10 @@ def emit_setting_changed_event(user, db_table, setting_name, old_value, new_valu
|
||||
truncated_fields
|
||||
)
|
||||
|
||||
# Announce field change
|
||||
USER_FIELD_CHANGED.send(sender=None, user=user, table=db_table, setting=setting_name,
|
||||
old_value=old_value, new_value=new_value)
|
||||
|
||||
|
||||
def _get_truncated_setting_value(value, max_length=None):
|
||||
"""
|
||||
|
||||
0
lms/djangoapps/email_marketing/__init__.py
Normal file
0
lms/djangoapps/email_marketing/__init__.py
Normal file
8
lms/djangoapps/email_marketing/admin.py
Normal file
8
lms/djangoapps/email_marketing/admin.py
Normal file
@@ -0,0 +1,8 @@
|
||||
""" Admin site bindings for email marketing """
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from email_marketing.models import EmailMarketingConfiguration
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
|
||||
admin.site.register(EmailMarketingConfiguration, ConfigurationModelAdmin)
|
||||
50
lms/djangoapps/email_marketing/migrations/0001_initial.py
Normal file
50
lms/djangoapps/email_marketing/migrations/0001_initial.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EmailMarketingConfiguration',
|
||||
fields=[
|
||||
('id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
|
||||
('change_date',
|
||||
models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
|
||||
|
||||
('enabled',
|
||||
models.BooleanField(default=False, verbose_name='Enabled')),
|
||||
|
||||
('sailthru_key',
|
||||
models.CharField(help_text='Sailthru api key.', max_length=32, null=True, blank=True)),
|
||||
|
||||
('sailthru_secret',
|
||||
models.CharField(help_text='Sailthru secret.', max_length=32, null=True, blank=True)),
|
||||
|
||||
('sailthru_new_user_list',
|
||||
models.CharField(help_text='Sailthru new user list.', max_length=48, null=True, blank=True)),
|
||||
|
||||
('sailthru_retry_interval',
|
||||
models.IntegerField(default=3600, help_text='Sailthru connection retry interval (secs).')),
|
||||
|
||||
('sailthru_max_retries',
|
||||
models.IntegerField(default=24, help_text='Sailthru maximum retries.')),
|
||||
|
||||
('sailthru_activation_template',
|
||||
models.CharField(help_text='Sailthru activation template.', max_length=20, null=True, blank=True)),
|
||||
|
||||
('changed_by',
|
||||
models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
|
||||
],
|
||||
),
|
||||
]
|
||||
57
lms/djangoapps/email_marketing/models.py
Normal file
57
lms/djangoapps/email_marketing/models.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Email-marketing-related models.
|
||||
"""
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from config_models.models import ConfigurationModel
|
||||
|
||||
|
||||
class EmailMarketingConfiguration(ConfigurationModel):
|
||||
""" Email marketing configuration """
|
||||
|
||||
class Meta(object):
|
||||
app_label = "email_marketing"
|
||||
|
||||
sailthru_key = models.fields.CharField(
|
||||
max_length=32,
|
||||
help_text=_(
|
||||
"API key for accessing Sailthru. "
|
||||
)
|
||||
)
|
||||
|
||||
sailthru_secret = models.fields.CharField(
|
||||
max_length=32,
|
||||
help_text=_(
|
||||
"API secret for accessing Sailthru. "
|
||||
)
|
||||
)
|
||||
|
||||
sailthru_new_user_list = models.fields.CharField(
|
||||
max_length=48,
|
||||
help_text=_(
|
||||
"Sailthru list name to add new users to. "
|
||||
)
|
||||
)
|
||||
|
||||
sailthru_retry_interval = models.fields.IntegerField(
|
||||
default=3600,
|
||||
help_text=_(
|
||||
"Sailthru connection retry interval (secs)."
|
||||
)
|
||||
)
|
||||
|
||||
sailthru_max_retries = models.fields.IntegerField(
|
||||
default=24,
|
||||
help_text=_(
|
||||
"Sailthru maximum retries."
|
||||
)
|
||||
)
|
||||
|
||||
sailthru_activation_template = models.fields.CharField(
|
||||
max_length=20,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"Sailthru template to use on activation send. "
|
||||
)
|
||||
)
|
||||
144
lms/djangoapps/email_marketing/signals.py
Normal file
144
lms/djangoapps/email_marketing/signals.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
This module contains signals needed for email integration
|
||||
"""
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from student.models import CourseEnrollment, UNENROLL_DONE
|
||||
from student.cookies import CREATE_LOGON_COOKIE
|
||||
from student.views import REGISTER_USER
|
||||
from email_marketing.models import EmailMarketingConfiguration
|
||||
from util.model_utils import USER_FIELD_CHANGED
|
||||
from lms.djangoapps.email_marketing.tasks import update_user, update_user_email
|
||||
|
||||
from sailthru.sailthru_client import SailthruClient
|
||||
from sailthru.sailthru_error import SailthruClientError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# list of changed fields to pass to Sailthru
|
||||
CHANGED_FIELDNAMES = ['username', 'is_active', 'name', 'gender', 'education',
|
||||
'age', 'level_of_education', 'year_of_birth',
|
||||
'country']
|
||||
|
||||
|
||||
@receiver(UNENROLL_DONE)
|
||||
def handle_unenroll_done(sender, course_enrollment=None, skip_refund=False,
|
||||
**kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Signal receiver for unenrollments
|
||||
"""
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return
|
||||
|
||||
# TBD
|
||||
|
||||
|
||||
@receiver(CREATE_LOGON_COOKIE)
|
||||
def add_email_marketing_cookies(sender, response=None, user=None,
|
||||
**kwargs): # pylint: disable=unused-argument):
|
||||
"""
|
||||
Signal function for adding any cookies needed for email marketing
|
||||
|
||||
Args:
|
||||
response: http response object
|
||||
user: The user object for the user being changed
|
||||
|
||||
Returns:
|
||||
response: http response object with cookie added
|
||||
"""
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return response
|
||||
|
||||
try:
|
||||
sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret)
|
||||
sailthru_response = \
|
||||
sailthru_client.api_post("user", {'id': user.email, 'fields': {'keys': 1},
|
||||
'vars': {'last_login_date':
|
||||
datetime.datetime.now().strftime("%Y-%m-%d")}})
|
||||
except SailthruClientError as exc:
|
||||
log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc))
|
||||
return response
|
||||
|
||||
if sailthru_response.is_ok():
|
||||
if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']:
|
||||
cookie = sailthru_response.json['keys']['cookie']
|
||||
|
||||
response.set_cookie(
|
||||
'sailthru_hid',
|
||||
cookie,
|
||||
max_age=365 * 24 * 60 * 60 # set for 1 year
|
||||
)
|
||||
else:
|
||||
log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email)
|
||||
else:
|
||||
error = sailthru_response.get_error()
|
||||
log.error("Error attempting to obtain cookie from Sailthru: %s", error.get_message())
|
||||
return response
|
||||
|
||||
|
||||
@receiver(REGISTER_USER)
|
||||
def email_marketing_register_user(sender, user=None, profile=None,
|
||||
**kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Called after user created and saved
|
||||
|
||||
Args:
|
||||
sender: Not used
|
||||
user: The user object for the user being changed
|
||||
profile: The user profile for the user being changed
|
||||
kwargs: Not used
|
||||
"""
|
||||
log.info("Receiving REGISTER_USER")
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return
|
||||
|
||||
# ignore anonymous users
|
||||
if user.is_anonymous():
|
||||
return
|
||||
|
||||
# perform update asynchronously
|
||||
update_user.delay(user.username, new_user=True)
|
||||
|
||||
|
||||
@receiver(USER_FIELD_CHANGED)
|
||||
def email_marketing_user_field_changed(sender, user=None, table=None, setting=None,
|
||||
old_value=None, new_value=None, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Update a single user/profile field
|
||||
|
||||
Args:
|
||||
sender: Not used
|
||||
user: The user object for the user being changed
|
||||
table: The name of the table being updated
|
||||
setting: The name of the setting being updated
|
||||
old_value: Prior value
|
||||
new_value: New value
|
||||
kwargs: Not used
|
||||
"""
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return
|
||||
|
||||
# ignore anonymous users
|
||||
if user.is_anonymous():
|
||||
return
|
||||
|
||||
# ignore anything but User or Profile table
|
||||
if table != 'auth_user' and table != 'auth_userprofile':
|
||||
return
|
||||
|
||||
# ignore anything not in list of fields to handle
|
||||
if setting in CHANGED_FIELDNAMES:
|
||||
# perform update asynchronously, flag if activation
|
||||
update_user.delay(user.username, new_user=False,
|
||||
activation=(setting == 'is_active') and new_value is True)
|
||||
|
||||
elif setting == 'email':
|
||||
# email update is special case
|
||||
update_user_email.delay(user.username, old_value)
|
||||
3
lms/djangoapps/email_marketing/startup.py
Normal file
3
lms/djangoapps/email_marketing/startup.py
Normal file
@@ -0,0 +1,3 @@
|
||||
""" email_marketing app. """
|
||||
# this is here to support registering the signals in signals.py
|
||||
from email_marketing import signals
|
||||
158
lms/djangoapps/email_marketing/tasks.py
Normal file
158
lms/djangoapps/email_marketing/tasks.py
Normal file
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
This file contains celery tasks for email marketing signal handler.
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
|
||||
from pytz import UTC
|
||||
|
||||
from celery import task
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from student.models import UserProfile
|
||||
from email_marketing.models import EmailMarketingConfiguration
|
||||
|
||||
from sailthru.sailthru_client import SailthruClient
|
||||
from sailthru.sailthru_error import SailthruClientError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# pylint: disable=not-callable
|
||||
@task(bind=True, default_retry_delay=3600, max_retries=24)
|
||||
def update_user(self, username, new_user=False, activation=False):
|
||||
"""
|
||||
Adds/updates Sailthru profile information for a user.
|
||||
Args:
|
||||
username(str): A string representation of user identifier
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return
|
||||
|
||||
# get user
|
||||
user = User.objects.select_related('profile').get(username=username)
|
||||
if not user:
|
||||
log.error("User not found during Sailthru update %s", username)
|
||||
return
|
||||
|
||||
# ignore anonymous users
|
||||
if user.is_anonymous():
|
||||
return
|
||||
|
||||
# get profile
|
||||
profile = user.profile
|
||||
if not profile:
|
||||
log.error("User profile not found during Sailthru update %s", username)
|
||||
return
|
||||
|
||||
sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret)
|
||||
try:
|
||||
sailthru_response = sailthru_client.api_post("user",
|
||||
_create_sailthru_user_parm(user, profile, new_user, email_config))
|
||||
except SailthruClientError as exc:
|
||||
log.error("Exception attempting to add/update user %s in Sailthru - %s", username, unicode(exc))
|
||||
raise self.retry(exc=exc,
|
||||
countdown=email_config.sailthru_retry_interval,
|
||||
max_retries=email_config.sailthru_max_retries)
|
||||
|
||||
if not sailthru_response.is_ok():
|
||||
error = sailthru_response.get_error()
|
||||
# put out error and schedule retry
|
||||
log.error("Error attempting to add/update user in Sailthru: %s", error.get_message())
|
||||
raise self.retry(countdown=email_config.sailthru_retry_interval,
|
||||
max_retries=email_config.sailthru_max_retries)
|
||||
|
||||
# if activating user, send welcome email
|
||||
if activation and email_config.sailthru_activation_template:
|
||||
try:
|
||||
sailthru_response = sailthru_client.api_post("send",
|
||||
{"email": user.email,
|
||||
"template": email_config.sailthru_activation_template})
|
||||
except SailthruClientError as exc:
|
||||
log.error("Exception attempting to send welcome email to user %s in Sailthru - %s", username, unicode(exc))
|
||||
raise self.retry(exc=exc,
|
||||
countdown=email_config.sailthru_retry_interval,
|
||||
max_retries=email_config.sailthru_max_retries)
|
||||
|
||||
if not sailthru_response.is_ok():
|
||||
error = sailthru_response.get_error()
|
||||
# probably an invalid template name, just put out error
|
||||
log.error("Error attempting to send welcome email to user in Sailthru: %s", error.get_message())
|
||||
|
||||
|
||||
# pylint: disable=not-callable
|
||||
@task(bind=True, default_retry_delay=3600, max_retries=24)
|
||||
def update_user_email(self, username, old_email):
|
||||
"""
|
||||
Adds/updates Sailthru when a user email address is changed
|
||||
Args:
|
||||
username(str): A string representation of user identifier
|
||||
old_email(str): Original email address
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
email_config = EmailMarketingConfiguration.current()
|
||||
if not email_config.enabled:
|
||||
return
|
||||
|
||||
# get user
|
||||
user = User.objects.get(username=username)
|
||||
if not user:
|
||||
log.error("User not found duing Sailthru update %s", username)
|
||||
return
|
||||
|
||||
# ignore anonymous users
|
||||
if user.is_anonymous():
|
||||
return
|
||||
|
||||
# ignore if email not changed
|
||||
if user.email == old_email:
|
||||
return
|
||||
|
||||
sailthru_parms = {"id": old_email, "key": "email", "keysconflict": "merge", "keys": {"email": user.email}}
|
||||
|
||||
try:
|
||||
sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret)
|
||||
sailthru_response = sailthru_client.api_post("user", sailthru_parms)
|
||||
except SailthruClientError as exc:
|
||||
log.error("Exception attempting to update email for %s in Sailthru - %s", username, unicode(exc))
|
||||
raise self.retry(exc=exc,
|
||||
countdown=email_config.sailthru_retry_interval,
|
||||
max_retries=email_config.sailthru_max_retries)
|
||||
|
||||
if not sailthru_response.is_ok():
|
||||
error = sailthru_response.get_error()
|
||||
log.error("Error attempting to update user email address in Sailthru: %s", error.get_message())
|
||||
raise self.retry(countdown=email_config.sailthru_retry_interval,
|
||||
max_retries=email_config.sailthru_max_retries)
|
||||
|
||||
|
||||
def _create_sailthru_user_parm(user, profile, new_user, email_config):
|
||||
"""
|
||||
Create sailthru user create/update parms from user + profile.
|
||||
"""
|
||||
sailthru_user = {'id': user.email, 'key': 'email'}
|
||||
sailthru_vars = {'username': user.username,
|
||||
'activated': int(user.is_active),
|
||||
'joined_date': user.date_joined.strftime("%Y-%m-%d")}
|
||||
sailthru_user['vars'] = sailthru_vars
|
||||
sailthru_vars['last_changed_time'] = int(time.time())
|
||||
|
||||
if profile:
|
||||
sailthru_vars['fullname'] = profile.name
|
||||
sailthru_vars['gender'] = profile.gender
|
||||
sailthru_vars['education'] = profile.level_of_education
|
||||
# age is not useful since it is not automatically updated
|
||||
#sailthru_vars['age'] = profile.age or -1
|
||||
if profile.year_of_birth:
|
||||
sailthru_vars['year_of_birth'] = profile.year_of_birth
|
||||
sailthru_vars['country'] = unicode(profile.country.code)
|
||||
|
||||
# if new user add to list
|
||||
if new_user and email_config.sailthru_new_user_list:
|
||||
sailthru_user['lists'] = {email_config.sailthru_new_user_list: 1}
|
||||
|
||||
return sailthru_user
|
||||
178
lms/djangoapps/email_marketing/tests/test_signals.py
Normal file
178
lms/djangoapps/email_marketing/tests/test_signals.py
Normal file
@@ -0,0 +1,178 @@
|
||||
"""Tests of email marketing signal handlers."""
|
||||
import logging
|
||||
import ddt
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from mock import patch
|
||||
from util.json_request import JsonResponse
|
||||
|
||||
from email_marketing.signals import handle_unenroll_done, \
|
||||
email_marketing_register_user, \
|
||||
email_marketing_user_field_changed, \
|
||||
add_email_marketing_cookies
|
||||
from email_marketing.tasks import update_user, update_user_email
|
||||
from email_marketing.models import EmailMarketingConfiguration
|
||||
from django.test.client import RequestFactory
|
||||
from student.tests.factories import UserFactory, UserProfileFactory
|
||||
|
||||
from sailthru.sailthru_client import SailthruClient
|
||||
from sailthru.sailthru_response import SailthruResponse
|
||||
from sailthru.sailthru_error import SailthruClientError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
TEST_EMAIL = "test@edx.org"
|
||||
|
||||
|
||||
def update_email_marketing_config(enabled=False, key='badkey', secret='badsecret', new_user_list='new list',
|
||||
template='Activation'):
|
||||
"""
|
||||
Enable / Disable Sailthru integration
|
||||
"""
|
||||
EmailMarketingConfiguration.objects.create(
|
||||
enabled=enabled,
|
||||
sailthru_key=key,
|
||||
sailthru_secret=secret,
|
||||
sailthru_new_user_list=new_user_list,
|
||||
sailthru_activation_template=template
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class EmailMarketingTests(TestCase):
|
||||
"""
|
||||
Tests for the EmailMarketing signals and tasks classes.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.request_factory = RequestFactory()
|
||||
self.user = UserFactory.create(username='test', email=TEST_EMAIL)
|
||||
self.profile = self.user.profile
|
||||
self.request = self.request_factory.get("foo")
|
||||
update_email_marketing_config(enabled=True)
|
||||
super(EmailMarketingTests, self).setUp()
|
||||
|
||||
@patch('email_marketing.signals.SailthruClient.api_post')
|
||||
def test_drop_cookie(self, mock_sailthru):
|
||||
"""
|
||||
Test add_email_marketing_cookies
|
||||
"""
|
||||
response = JsonResponse({
|
||||
"success": True,
|
||||
"redirect_url": 'test.com/test',
|
||||
})
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'keys': {'cookie': 'test_cookie'}}))
|
||||
add_email_marketing_cookies(None, response=response, user=self.user)
|
||||
self.assertTrue('sailthru_hid' in response.cookies)
|
||||
self.assertEquals(mock_sailthru.call_args[0][0], "user")
|
||||
userparms = mock_sailthru.call_args[0][1]
|
||||
self.assertEquals(userparms['fields']['keys'], 1)
|
||||
self.assertEquals(userparms['id'], TEST_EMAIL)
|
||||
self.assertEquals(response.cookies['sailthru_hid'].value, "test_cookie")
|
||||
|
||||
@patch('email_marketing.signals.SailthruClient.api_post')
|
||||
def test_drop_cookie_error_path(self, mock_sailthru):
|
||||
"""
|
||||
test that error paths return no cookie
|
||||
"""
|
||||
response = JsonResponse({
|
||||
"success": True,
|
||||
"redirect_url": 'test.com/test',
|
||||
})
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'keys': {'cookiexx': 'test_cookie'}}))
|
||||
add_email_marketing_cookies(None, response=response, user=self.user)
|
||||
self.assertFalse('sailthru_hid' in response.cookies)
|
||||
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'error': "error", "errormsg": "errormsg"}))
|
||||
add_email_marketing_cookies(None, response=response, user=self.user)
|
||||
self.assertFalse('sailthru_hid' in response.cookies)
|
||||
|
||||
mock_sailthru.side_effect = SailthruClientError
|
||||
add_email_marketing_cookies(None, response=response, user=self.user)
|
||||
self.assertFalse('sailthru_hid' in response.cookies)
|
||||
|
||||
@patch('email_marketing.tasks.log.error')
|
||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||
def test_add_user(self, mock_sailthru, mock_log_error):
|
||||
"""
|
||||
test async method in tasks that actually updates Sailthru
|
||||
"""
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||
update_user.delay(self.user.username, new_user=True)
|
||||
self.assertFalse(mock_log_error.called)
|
||||
self.assertEquals(mock_sailthru.call_args[0][0], "user")
|
||||
userparms = mock_sailthru.call_args[0][1]
|
||||
self.assertEquals(userparms['key'], "email")
|
||||
self.assertEquals(userparms['id'], TEST_EMAIL)
|
||||
self.assertEquals(userparms['vars']['gender'], "m")
|
||||
self.assertEquals(userparms['vars']['username'], "test")
|
||||
self.assertEquals(userparms['vars']['activated'], 1)
|
||||
self.assertEquals(userparms['lists']['new list'], 1)
|
||||
|
||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||
def test_activation(self, mock_sailthru):
|
||||
"""
|
||||
test send of activation template
|
||||
"""
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||
update_user.delay(self.user.username, new_user=True, activation=True)
|
||||
# look for call args for 2nd call
|
||||
self.assertEquals(mock_sailthru.call_args[0][0], "send")
|
||||
userparms = mock_sailthru.call_args[0][1]
|
||||
self.assertEquals(userparms['email'], TEST_EMAIL)
|
||||
self.assertEquals(userparms['template'], "Activation")
|
||||
|
||||
@patch('email_marketing.tasks.log.error')
|
||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||
def test_error_logging(self, mock_sailthru, mock_log_error):
|
||||
"""
|
||||
Ensure that error returned from Sailthru api is logged
|
||||
"""
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))
|
||||
update_user.delay(self.user.username)
|
||||
self.assertTrue(mock_log_error.called)
|
||||
|
||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||
def test_change_email(self, mock_sailthru):
|
||||
"""
|
||||
test async method in task that changes email in Sailthru
|
||||
"""
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||
#self.user.email = "newemail@test.com"
|
||||
update_user_email.delay(self.user.username, "old@edx.org")
|
||||
self.assertEquals(mock_sailthru.call_args[0][0], "user")
|
||||
userparms = mock_sailthru.call_args[0][1]
|
||||
self.assertEquals(userparms['key'], "email")
|
||||
self.assertEquals(userparms['id'], "old@edx.org")
|
||||
self.assertEquals(userparms['keys']['email'], TEST_EMAIL)
|
||||
|
||||
@patch('email_marketing.tasks.log.error')
|
||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||
def test_error_logging1(self, mock_sailthru, mock_log_error):
|
||||
"""
|
||||
Ensure that error returned from Sailthru api is logged
|
||||
"""
|
||||
mock_sailthru.return_value = SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))
|
||||
update_user_email.delay(self.user.username, "newemail2@test.com")
|
||||
self.assertTrue(mock_log_error.called)
|
||||
|
||||
@patch('lms.djangoapps.email_marketing.tasks.update_user.delay')
|
||||
def test_register_user(self, mock_update_user):
|
||||
"""
|
||||
make sure register user call invokes update_user
|
||||
"""
|
||||
email_marketing_register_user(None, user=self.user, profile=self.profile)
|
||||
self.assertTrue(mock_update_user.called)
|
||||
|
||||
@patch('lms.djangoapps.email_marketing.tasks.update_user.delay')
|
||||
@ddt.data(('auth_userprofile', 'gender', 'f', True),
|
||||
('auth_user', 'is_active', 1, True),
|
||||
('auth_userprofile', 'shoe_size', 1, False))
|
||||
@ddt.unpack
|
||||
def test_modify_field(self, table, setting, value, result, mock_update_user):
|
||||
"""
|
||||
Test that correct fields call update_user
|
||||
"""
|
||||
email_marketing_user_field_changed(None, self.user, table=table, setting=setting, new_value=value)
|
||||
self.assertEqual(mock_update_user.called, result)
|
||||
@@ -2070,6 +2070,9 @@ INSTALLED_APPS = (
|
||||
|
||||
# Enables default site and redirects
|
||||
'django_sites_extensions',
|
||||
|
||||
# Email marketing integration
|
||||
'email_marketing',
|
||||
)
|
||||
|
||||
# Migrations which are not in the standard module "migrations"
|
||||
|
||||
@@ -180,3 +180,6 @@ jsonfield==1.0.3
|
||||
|
||||
# Inlines CSS styles into HTML for email notifications.
|
||||
pynliner==0.5.2
|
||||
|
||||
# for sailthru integration
|
||||
sailthru-client==2.2.3
|
||||
|
||||
Reference in New Issue
Block a user