def check_get_user(self, master, optin, confirm, error, expected_result): """ Call get_user_data with the given conditions and verify that the return value matches the expected result. The expected result can include `ANY` values for don't-cares. :param master: What should be returned if we query the master DB :param optin: What should be returned if we query the opt-in DB :param confirm: What should be returned if we query the confirmed DB :param error: Exception to raise :param expected_result: Expected return value of get_user_data, or expected exception raised if any """ # Use this method to mock look_for_user so that we can return # different values given the input arguments def mock_look_for_user(database, email, token, fields): if error: raise error if database == settings.EXACTTARGET_DATA: return master elif database == settings.EXACTTARGET_OPTIN_STAGE: return optin elif database == settings.EXACTTARGET_CONFIRMATION: return optin else: raise Exception("INVALID INPUT TO mock_look_for_user - " "database %r unknown" % database) with patch('news.views.look_for_user') as look_for_user: look_for_user.side_effect = mock_look_for_user result = get_user_data() self.assertEqual(expected_result, result)
def send_recovery_message_task(email): # Have to import here to avoid circular import - that means that for # testing, this can't be mocked. Mock look_for_user instead. from news.views import get_user_data # We should check ET so we can get format and lang if they exist. # If they don't exist, then we can create a basket subscriber. user_data = get_user_data(email=email, sync_data=True) if not user_data: log.warn("In send_recovery_message_task, email not known: %s" % email) return # make sure we have a language and format, no matter what ET returned lang = user_data.get('lang', 'en') or 'en' format = user_data.get('format', 'H') or 'H' message_id = mogrify_message_id(RECOVERY_MESSAGE_ID, lang, format) send_message(message_id, email, user_data['token'], format)
def confirm_user(token, user_data): """ Confirm any pending subscriptions for the user with this token. If any of the subscribed newsletters have welcome messages, send them. :param token: User's token :param user_data: Dictionary with user's data from Exact Target, as returned by get_user_data(), or None if that wasn't available when this was called. :raises: BasketError for fatal errors, NewsletterException for retryable errors. """ # Get user data if we don't already have it if user_data is None: from .views import get_user_data # Avoid circular import user_data = get_user_data(token=token) if user_data is None: log.error(MSG_USER_NOT_FOUND) raise BasketError(MSG_USER_NOT_FOUND) if user_data['status'] == 'error': msg = "error getting user data for %s: %s" % \ (token, user_data['desc']) log.error(msg) raise NewsletterException(msg) if user_data['confirmed']: log.info("In confirm_user, user with token %s " "is already confirmed" % token) return if not 'email' in user_data or not user_data['email']: msg = "in confirm_user, token %s has no email addr in ET" % token log.error(msg) raise BasketError(msg) # Add user's token to the confirmation database at ET. A nightly # task will somehow do something about it. apply_updates(settings.EXACTTARGET_CONFIRMATION, {'TOKEN': token}) # Now, if they're subscribed to any newsletters with confirmation # welcome messages, send those. send_welcomes(user_data, user_data['newsletters'], user_data.get('format', 'H'))
def update_user(data, email, token, created, type, optin): """Task for updating user's preferences and newsletters. :param dict data: POST data from the form submission :param string email: User's email address :param string token: User's token :param boolean created: Whether a new user was created in Basket :param int type: What kind of API call it was. Could be SUBSCRIBE, UNSUBSCRIBE, or SET. :param boolean optin: Whether the user should go through the double-optin process or not. If ``optin`` is ``True`` then the user should bypass the double-optin process. :returns: One of the return codes UU_ALREADY_CONFIRMED, etc. (see code) to indicate what case we figured out we were doing. (These are primarily for tests to use.) :raises: NewsletterException if there are any errors that would be worth retrying. Our task wrapper will retry in that case. """ # Parse the parameters # `record` will contain the data we send to ET in the format they want. record = { 'EMAIL_ADDRESS_': email, 'TOKEN': token, 'EMAIL_PERMISSION_STATUS_': 'I', 'MODIFIED_DATE_': gmttime(), } extra_fields = { 'country': 'COUNTRY_', 'lang': 'LANGUAGE_ISO2', 'source_url': 'SOURCE_URL', } # Optionally add more fields for field in extra_fields: if field in data: record[extra_fields[field]] = data[field] lang = record.get('LANGUAGE_ISO2', '') or '' # Can't import this earlier, circular import from .views import get_user_data # Get the user's current settings from ET, if any user_data = get_user_data(token=token) # If we don't find the user, get_user_data returns None. Create # a minimal dictionary to use going forward. This will happen # often due to new people signing up. if user_data is None: user_data = { 'email': email, 'token': token, 'master': False, 'pending': False, 'confirmed': False, 'lang': lang, 'status': 'ok', } elif user_data.get('status', 'error') != 'ok': # Error talking to ET - raise so we retry later msg = "Some error with Exact Target: %r" % user_data raise NewsletterException(msg) if lang: # User asked for a language change. Use the new language from # here on. user_data['lang'] = lang else: # Use `lang` as a shorter reference to user_data['lang'] lang = user_data['lang'] # We need an HTML/Text format choice for sending welcome messages, and # optionally to update their ET record if 'format' in data: # Submitted in call fmt = 'T' if data.get('format', 'H').upper().startswith('T') else 'H' # We only set the format in ET if the call asked us to record['EMAIL_FORMAT_'] = fmt elif 'format' in user_data: # Existing user preference fmt = user_data['format'] else: # Default to 'H' fmt = 'H' # From here on, fmt is either 'H' or 'T', preferring 'H' newsletters = [x.strip() for x in data.get('newsletters', '').split(',')] cur_newsletters = user_data.get('newsletters', None) if cur_newsletters is not None: cur_newsletters = set(cur_newsletters) # Set the newsletter flags in the record by comparing to their # current subscriptions. to_subscribe, to_unsubscribe = parse_newsletters(record, type, newsletters, cur_newsletters) # Are they subscribing to any newsletters that don't require confirmation? # When including any newsletter that does not # require confirmation, user gets a pass on confirming and goes straight # to confirmed. exempt_from_confirmation = optin or Newsletter.objects\ .filter(slug__in=to_subscribe, requires_double_optin=False)\ .exists() # Send welcomes when type is SUBSCRIBE and trigger_welcome arg # is absent or 'Y'. should_send_welcomes = data.get('trigger_welcome', 'Y') == 'Y'\ and type == SUBSCRIBE MASTER = settings.EXACTTARGET_DATA OPT_IN = settings.EXACTTARGET_OPTIN_STAGE if user_data['confirmed']: # The user is already confirmed. # Just add any new subs to whichever of master or optin list is # appropriate, and send welcomes. target_et = MASTER if user_data['master'] else OPT_IN apply_updates(target_et, record) if should_send_welcomes: send_welcomes(user_data, to_subscribe, fmt) return_code = UU_ALREADY_CONFIRMED elif exempt_from_confirmation: # This user is not confirmed, but they # qualify to be excepted from confirmation. if user_data['pending']: # We were waiting for them to confirm. Update the data in # their record (currently in the Opt-in table), then go # ahead and confirm them. This will also send welcomes. apply_updates(OPT_IN, record) confirm_user(user_data['token'], user_data) return_code = UU_EXEMPT_PENDING else: # Brand new user: Add them directly to master subscriber DB # and send welcomes. record['CREATED_DATE_'] = gmttime() apply_updates(MASTER, record) if should_send_welcomes: send_welcomes(user_data, to_subscribe, fmt) return_code = UU_EXEMPT_NEW else: # This user must confirm if user_data['pending']: return_code = UU_MUST_CONFIRM_PENDING else: # Creating a new record, need a couple more fields record['CREATED_DATE_'] = gmttime() record['SubscriberKey'] = record['TOKEN'] record['EmailAddress'] = record['EMAIL_ADDRESS_'] return_code = UU_MUST_CONFIRM_NEW # Create or update OPT_IN record and send email telling them (or # reminding them) to confirm. apply_updates(OPT_IN, record) send_confirm_notice(email, token, lang, fmt, to_subscribe) return return_code