Merge pull request #15731 from edx/waheed/LEARNER-2039-send-welcome-email-on-new-user-creation
Send welcome email to inactive learners on registration.
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('email_marketing', '0006_auto_20170711_0615'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='emailmarketingconfiguration',
|
||||||
|
old_name='sailthru_activation_template',
|
||||||
|
new_name='sailthru_welcome_template'
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='emailmarketingconfiguration',
|
||||||
|
name='sailthru_welcome_template',
|
||||||
|
field=models.CharField(help_text='Sailthru template to use on welcome send. ', max_length=20, blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='emailmarketingconfiguration',
|
||||||
|
name='welcome_email_send_delay',
|
||||||
|
field=models.IntegerField(default=600, help_text='Number of seconds to delay the sending of User Welcome email after user has been created'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -47,11 +47,11 @@ class EmailMarketingConfiguration(ConfigurationModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
sailthru_activation_template = models.fields.CharField(
|
sailthru_welcome_template = models.fields.CharField(
|
||||||
max_length=20,
|
max_length=20,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Sailthru template to use on activation send. "
|
"Sailthru template to use on welcome send. "
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ class EmailMarketingConfiguration(ConfigurationModel):
|
|||||||
welcome_email_send_delay = models.fields.IntegerField(
|
welcome_email_send_delay = models.fields.IntegerField(
|
||||||
default=600,
|
default=600,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Number of seconds to delay the sending of User Welcome email after user has been activated"
|
"Number of seconds to delay the sending of User Welcome email after user has been created"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -145,5 +145,5 @@ class EmailMarketingConfiguration(ConfigurationModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Email marketing configuration: New user list %s, Activation template: %s" % \
|
return u"Email marketing configuration: New user list %s, Welcome template: %s" % \
|
||||||
(self.sailthru_new_user_list, self.sailthru_activation_template)
|
(self.sailthru_new_user_list, self.sailthru_welcome_template)
|
||||||
|
|||||||
@@ -149,9 +149,9 @@ def email_marketing_user_field_changed(sender, user=None, table=None, setting=No
|
|||||||
if not email_config.enabled:
|
if not email_config.enabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
# perform update asynchronously, flag if activation
|
# perform update asynchronously
|
||||||
update_user.delay(_create_sailthru_user_vars(user, user.profile), user.email, site=_get_current_site(),
|
update_user.delay(_create_sailthru_user_vars(user, user.profile), user.email, site=_get_current_site(),
|
||||||
new_user=False, activation=(setting == 'is_active') and new_value is True)
|
new_user=False)
|
||||||
|
|
||||||
elif setting == 'email':
|
elif setting == 'email':
|
||||||
# email update is special case
|
# email update is special case
|
||||||
|
|||||||
@@ -59,14 +59,13 @@ def get_email_cookies_via_sailthru(self, user_email, post_parms):
|
|||||||
|
|
||||||
# pylint: disable=not-callable
|
# pylint: disable=not-callable
|
||||||
@task(bind=True, default_retry_delay=3600, max_retries=24)
|
@task(bind=True, default_retry_delay=3600, max_retries=24)
|
||||||
def update_user(self, sailthru_vars, email, site=None, new_user=False, activation=False):
|
def update_user(self, sailthru_vars, email, site=None, new_user=False):
|
||||||
"""
|
"""
|
||||||
Adds/updates Sailthru profile information for a user.
|
Adds/updates Sailthru profile information for a user.
|
||||||
Args:
|
Args:
|
||||||
sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru
|
sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru
|
||||||
email(str): User email address
|
email(str): User email address
|
||||||
new_user(boolean): True if new registration
|
new_user(boolean): True if new registration
|
||||||
activation(boolean): True if activation request
|
|
||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
@@ -95,15 +94,15 @@ def update_user(self, sailthru_vars, email, site=None, new_user=False, activatio
|
|||||||
max_retries=email_config.sailthru_max_retries)
|
max_retries=email_config.sailthru_max_retries)
|
||||||
return
|
return
|
||||||
|
|
||||||
# if activating user, send welcome email
|
# if new user, send welcome email
|
||||||
if activation and email_config.sailthru_activation_template:
|
if new_user and email_config.sailthru_welcome_template:
|
||||||
scheduled_datetime = datetime.utcnow() + timedelta(seconds=email_config.welcome_email_send_delay)
|
scheduled_datetime = datetime.utcnow() + timedelta(seconds=email_config.welcome_email_send_delay)
|
||||||
try:
|
try:
|
||||||
sailthru_response = sailthru_client.api_post(
|
sailthru_response = sailthru_client.api_post(
|
||||||
"send",
|
"send",
|
||||||
{
|
{
|
||||||
"email": email,
|
"email": email,
|
||||||
"template": email_config.sailthru_activation_template,
|
"template": email_config.sailthru_welcome_template,
|
||||||
"schedule_time": scheduled_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')
|
"schedule_time": scheduled_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ TEST_EMAIL = "test@edx.org"
|
|||||||
|
|
||||||
|
|
||||||
def update_email_marketing_config(enabled=True, key='badkey', secret='badsecret', new_user_list='new list',
|
def update_email_marketing_config(enabled=True, key='badkey', secret='badsecret', new_user_list='new list',
|
||||||
template='Activation', enroll_cost=100, lms_url_override='http://testserver'):
|
template='Welcome', enroll_cost=100, lms_url_override='http://testserver'):
|
||||||
"""
|
"""
|
||||||
Enable / Disable Sailthru integration
|
Enable / Disable Sailthru integration
|
||||||
"""
|
"""
|
||||||
@@ -50,7 +50,7 @@ def update_email_marketing_config(enabled=True, key='badkey', secret='badsecret'
|
|||||||
sailthru_key=key,
|
sailthru_key=key,
|
||||||
sailthru_secret=secret,
|
sailthru_secret=secret,
|
||||||
sailthru_new_user_list=new_user_list,
|
sailthru_new_user_list=new_user_list,
|
||||||
sailthru_activation_template=template,
|
sailthru_welcome_template=template,
|
||||||
sailthru_enroll_template='enroll_template',
|
sailthru_enroll_template='enroll_template',
|
||||||
sailthru_lms_url_override=lms_url_override,
|
sailthru_lms_url_override=lms_url_override,
|
||||||
sailthru_get_tags_from_sailthru=False,
|
sailthru_get_tags_from_sailthru=False,
|
||||||
@@ -175,7 +175,7 @@ class EmailMarketingTests(TestCase):
|
|||||||
@patch('email_marketing.tasks.SailthruClient.api_get')
|
@patch('email_marketing.tasks.SailthruClient.api_get')
|
||||||
def test_add_user(self, mock_sailthru_get, mock_sailthru_post, mock_log_error):
|
def test_add_user(self, mock_sailthru_get, mock_sailthru_post, mock_log_error):
|
||||||
"""
|
"""
|
||||||
test async method in tasks that actually updates Sailthru
|
test async method in tasks that actually updates Sailthru and send Welcome template.
|
||||||
"""
|
"""
|
||||||
site_dict = {'id': self.site.id, 'domain': self.site.domain, 'name': self.site.name}
|
site_dict = {'id': self.site.id, 'domain': self.site.domain, 'name': self.site.name}
|
||||||
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||||
@@ -183,15 +183,13 @@ class EmailMarketingTests(TestCase):
|
|||||||
update_user.delay(
|
update_user.delay(
|
||||||
{'gender': 'm', 'username': 'test', 'activated': 1}, TEST_EMAIL, site_dict, new_user=True
|
{'gender': 'm', 'username': 'test', 'activated': 1}, TEST_EMAIL, site_dict, new_user=True
|
||||||
)
|
)
|
||||||
|
expected_schedule = datetime.datetime.utcnow() + datetime.timedelta(seconds=600)
|
||||||
self.assertFalse(mock_log_error.called)
|
self.assertFalse(mock_log_error.called)
|
||||||
self.assertEquals(mock_sailthru_post.call_args[0][0], "user")
|
self.assertEquals(mock_sailthru_post.call_args[0][0], "send")
|
||||||
userparms = mock_sailthru_post.call_args[0][1]
|
userparms = mock_sailthru_post.call_args[0][1]
|
||||||
self.assertEquals(userparms['key'], "email")
|
self.assertEquals(userparms['email'], TEST_EMAIL)
|
||||||
self.assertEquals(userparms['id'], TEST_EMAIL)
|
self.assertEquals(userparms['template'], "Welcome")
|
||||||
self.assertEquals(userparms['vars']['gender'], "m")
|
self.assertEquals(userparms['schedule_time'], expected_schedule.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
||||||
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')
|
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||||
@patch('email_marketing.tasks.SailthruClient.api_get')
|
@patch('email_marketing.tasks.SailthruClient.api_get')
|
||||||
@@ -199,6 +197,8 @@ class EmailMarketingTests(TestCase):
|
|||||||
"""
|
"""
|
||||||
test non existing domain name updates Sailthru user lists with default list
|
test non existing domain name updates Sailthru user lists with default list
|
||||||
"""
|
"""
|
||||||
|
# Set template to empty string to disable 2nd post call to Sailthru
|
||||||
|
update_email_marketing_config(template='')
|
||||||
existing_site = Site.objects.create(domain='testing.com', name='testing.com')
|
existing_site = Site.objects.create(domain='testing.com', name='testing.com')
|
||||||
site_dict = {'id': existing_site.id, 'domain': existing_site.domain, 'name': existing_site.name}
|
site_dict = {'id': existing_site.id, 'domain': existing_site.domain, 'name': existing_site.name}
|
||||||
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||||
@@ -216,18 +216,16 @@ class EmailMarketingTests(TestCase):
|
|||||||
@patch('email_marketing.tasks.SailthruClient.api_get')
|
@patch('email_marketing.tasks.SailthruClient.api_get')
|
||||||
def test_user_activation(self, mock_sailthru_get, mock_sailthru_post):
|
def test_user_activation(self, mock_sailthru_get, mock_sailthru_post):
|
||||||
"""
|
"""
|
||||||
test send of activation template
|
Test that welcome template not sent if not new user.
|
||||||
"""
|
"""
|
||||||
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True}))
|
||||||
mock_sailthru_get.return_value = SailthruResponse(JsonResponse({'lists': [{'name': 'new list'}], 'ok': True}))
|
mock_sailthru_get.return_value = SailthruResponse(JsonResponse({'lists': [{'name': 'new list'}], 'ok': True}))
|
||||||
expected_schedule = datetime.datetime.utcnow() + datetime.timedelta(seconds=600)
|
update_user.delay({}, self.user.email, new_user=False)
|
||||||
update_user.delay({}, self.user.email, new_user=True, activation=True)
|
|
||||||
# look for call args for 2nd call
|
# look for call args for 2nd call
|
||||||
self.assertEquals(mock_sailthru_post.call_args[0][0], "send")
|
self.assertEquals(mock_sailthru_post.call_args[0][0], "user")
|
||||||
userparms = mock_sailthru_post.call_args[0][1]
|
userparms = mock_sailthru_post.call_args[0][1]
|
||||||
self.assertEquals(userparms['email'], TEST_EMAIL)
|
self.assertIsNone(userparms.get('email'))
|
||||||
self.assertEquals(userparms['template'], "Activation")
|
self.assertIsNone(userparms.get('template'))
|
||||||
self.assertEquals(userparms['schedule_time'], expected_schedule.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
|
||||||
|
|
||||||
@patch('email_marketing.tasks.log.error')
|
@patch('email_marketing.tasks.log.error')
|
||||||
@patch('email_marketing.tasks.SailthruClient.api_post')
|
@patch('email_marketing.tasks.SailthruClient.api_post')
|
||||||
@@ -248,14 +246,14 @@ class EmailMarketingTests(TestCase):
|
|||||||
# force Sailthru API exception on 2nd call
|
# force Sailthru API exception on 2nd call
|
||||||
mock_log_error.reset_mock()
|
mock_log_error.reset_mock()
|
||||||
mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})), SailthruClientError]
|
mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})), SailthruClientError]
|
||||||
update_user.delay({}, self.user.email, activation=True)
|
update_user.delay({}, self.user.email, new_user=True)
|
||||||
self.assertTrue(mock_log_error.called)
|
self.assertTrue(mock_log_error.called)
|
||||||
|
|
||||||
# force Sailthru API error return on 2nd call
|
# force Sailthru API error return on 2nd call
|
||||||
mock_log_error.reset_mock()
|
mock_log_error.reset_mock()
|
||||||
mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})),
|
mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})),
|
||||||
SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))]
|
SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))]
|
||||||
update_user.delay({}, self.user.email, activation=True)
|
update_user.delay({}, self.user.email, new_user=True)
|
||||||
self.assertTrue(mock_log_error.called)
|
self.assertTrue(mock_log_error.called)
|
||||||
|
|
||||||
@patch('email_marketing.tasks.update_user.retry')
|
@patch('email_marketing.tasks.update_user.retry')
|
||||||
|
|||||||
Reference in New Issue
Block a user