diff --git a/common/djangoapps/third_party_auth/migrations/0017_auto_20180327_1631.py b/common/djangoapps/third_party_auth/migrations/0017_auto_20180327_1631.py new file mode 100644 index 0000000000..0bc41efc83 --- /dev/null +++ b/common/djangoapps/third_party_auth/migrations/0017_auto_20180327_1631.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('third_party_auth', '0016_auto_20180130_0938'), + ] + + operations = [ + migrations.AddField( + model_name='ltiproviderconfig', + name='send_welcome_email', + field=models.BooleanField(default=False, help_text='If this option is selected, users will be sent a welcome email upon registration.'), + ), + migrations.AddField( + model_name='oauth2providerconfig', + name='send_welcome_email', + field=models.BooleanField(default=False, help_text='If this option is selected, users will be sent a welcome email upon registration.'), + ), + migrations.AddField( + model_name='samlproviderconfig', + name='send_welcome_email', + field=models.BooleanField(default=False, help_text='If this option is selected, users will be sent a welcome email upon registration.'), + ), + ] diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index b2947d4a75..8166e6f6b8 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -147,6 +147,12 @@ class ProviderConfig(ConfigurationModel): "email, and their account will be activated immediately upon registration." ), ) + send_welcome_email = models.BooleanField( + default=False, + help_text=_( + "If this option is selected, users will be sent a welcome email upon registration." + ), + ) visible = models.BooleanField( default=False, help_text=_( diff --git a/lms/djangoapps/email_marketing/signals.py b/lms/djangoapps/email_marketing/signals.py index 462c4cfc77..0a28fb0364 100644 --- a/lms/djangoapps/email_marketing/signals.py +++ b/lms/djangoapps/email_marketing/signals.py @@ -11,6 +11,7 @@ from django.dispatch import receiver from sailthru.sailthru_error import SailthruClientError from celery.exceptions import TimeoutError +import third_party_auth from course_modes.models import CourseMode from email_marketing.models import EmailMarketingConfiguration from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace @@ -177,9 +178,27 @@ def email_marketing_user_field_changed(sender, user=None, table=None, setting=No if not email_config.enabled: return + # Is the status of the user account changing to active? + is_activation = (setting == 'is_active') and new_value is True + + # Is this change in the context of an SSO-initiated registration? + third_party_provider = None + if third_party_auth.is_enabled(): + running_pipeline = third_party_auth.pipeline.get(crum.get_current_request()) + if running_pipeline: + third_party_provider = third_party_auth.provider.Registry.get_from_pipeline(running_pipeline) + + # Send a welcome email if the user account is being activated + # and we are not in a SSO registration flow whose associated + # identity provider is configured to allow for the sending + # of a welcome email. + send_welcome_email = is_activation and ( + third_party_provider is None or third_party_provider.send_welcome_email + ) + # set the activation flag when the user is marked as activated 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, send_welcome_email=send_welcome_email) elif setting == 'email': # email update is special case diff --git a/lms/djangoapps/email_marketing/tasks.py b/lms/djangoapps/email_marketing/tasks.py index 2d9fbf9d5d..0e78e11b61 100644 --- a/lms/djangoapps/email_marketing/tasks.py +++ b/lms/djangoapps/email_marketing/tasks.py @@ -59,14 +59,14 @@ def get_email_cookies_via_sailthru(self, user_email, post_parms): # pylint: disable=not-callable @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, send_welcome_email=False): """ Adds/updates Sailthru profile information for a user. Args: sailthru_vars(dict): User profile information to pass as 'vars' to Sailthru email(str): User email address new_user(boolean): True if new registration - activation(boolean): True if activation request + send_welcome_email(boolean): True if a welcome email should be sent Returns: None """ @@ -95,8 +95,7 @@ def update_user(self, sailthru_vars, email, site=None, new_user=False, activatio max_retries=email_config.sailthru_max_retries) return - # if activating user, send welcome email - if activation and email_config.sailthru_welcome_template and is_default_site(site) and not \ + if send_welcome_email and email_config.sailthru_welcome_template and is_default_site(site) and not \ sailthru_vars.get('is_enterprise_learner'): scheduled_datetime = datetime.utcnow() + timedelta(seconds=email_config.welcome_email_send_delay) diff --git a/lms/djangoapps/email_marketing/tests/test_signals.py b/lms/djangoapps/email_marketing/tests/test_signals.py index 809275496a..1a0a2b2495 100644 --- a/lms/djangoapps/email_marketing/tests/test_signals.py +++ b/lms/djangoapps/email_marketing/tests/test_signals.py @@ -9,7 +9,7 @@ from django.contrib.sites.models import Site from django.test import TestCase from django.test.client import RequestFactory from freezegun import freeze_time -from mock import ANY, patch +from mock import ANY, Mock, patch from opaque_keys.edx.keys import CourseKey from sailthru.sailthru_error import SailthruClientError from sailthru.sailthru_response import SailthruResponse @@ -280,14 +280,14 @@ class EmailMarketingTests(TestCase): # force Sailthru API exception on 2nd call mock_log_error.reset_mock() mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})), SailthruClientError] - update_user.delay({}, self.user.email, activation=True) + update_user.delay({}, self.user.email, send_welcome_email=True) self.assertTrue(mock_log_error.called) # force Sailthru API error return on 2nd call mock_log_error.reset_mock() mock_sailthru.side_effect = [SailthruResponse(JsonResponse({'ok': True})), SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))] - update_user.delay({}, self.user.email, activation=True) + update_user.delay({}, self.user.email, send_welcome_email=True) self.assertTrue(mock_log_error.called) @patch('email_marketing.tasks.update_user.retry') @@ -509,6 +509,7 @@ class EmailMarketingTests(TestCase): email_marketing_register_user(None, user=self.user, registration=self.registration) self.assertEqual(mock_update_user.call_args[0][0]['ui_lang'], 'es-419') + @patch.dict(settings.FEATURES, {"ENABLE_THIRD_PARTY_AUTH": False}) @patch('email_marketing.signals.crum.get_current_request') @patch('lms.djangoapps.email_marketing.tasks.update_user.delay') @ddt.data(('auth_userprofile', 'gender', 'f', True), @@ -524,6 +525,26 @@ class EmailMarketingTests(TestCase): email_marketing_user_field_changed(None, self.user, table=table, setting=setting, new_value=value) self.assertEqual(mock_update_user.called, result) + @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('email_marketing.signals.third_party_auth.provider.Registry.get_from_pipeline') + @patch('email_marketing.signals.third_party_auth.pipeline.get') + @patch('email_marketing.signals.crum.get_current_request') + @ddt.data(True, False) + def test_modify_field_with_sso(self, send_welcome_email, mock_get_current_request, + mock_pipeline_get, mock_registry_get_from_pipeline, mock_sailthru_post): + """ + Test that welcome email is sent appropriately in the context of SSO registration + """ + mock_get_current_request.return_value = self.request + mock_pipeline_get.return_value = 'saml-idp' + mock_registry_get_from_pipeline.return_value = Mock(send_welcome_email=send_welcome_email) + mock_sailthru_post.return_value = SailthruResponse(JsonResponse({'ok': True})) + email_marketing_user_field_changed(None, self.user, table='auth_user', setting='is_active', new_value=True) + if send_welcome_email: + self.assertEqual(mock_sailthru_post.call_args[0][0], "send") + else: + self.assertNotEqual(mock_sailthru_post.call_args[0][0], "send") + @patch('lms.djangoapps.email_marketing.tasks.update_user.delay') def test_modify_language_preference(self, mock_update_user): """