Exemplo n.º 1
0
 def test_user_set_bad_language(self):
     """If the user view is sent a POST request with an invalid
     language, it fails.
     """
     token = generate_token()
     resp = self.client.post('/news/user/{}/'.format(token),
                             {'fake': 'data', 'lang': '55'})
     self.assertEqual(resp.status_code, 400)
     data = json.loads(resp.content)
     self.assertEqual(data['status'], 'error')
     self.assertEqual(data['desc'], 'invalid language')
Exemplo n.º 2
0
 def test_user_not_in_et(self, sfmc_mock):
     """A user not found in ET should produce an error response."""
     sfmc_mock.get_row.side_effect = NewsletterException('DANGER!')
     token = generate_token()
     resp = self.client.get('/news/user/{}/'.format(token))
     self.assertEqual(resp.status_code, 400)
     resp_data = json.loads(resp.content)
     self.assertDictEqual(resp_data, {
         'status': 'error',
         'desc': 'DANGER!',
         'code': errors.BASKET_NETWORK_FAILURE,
     })
Exemplo n.º 3
0
 def setUp(self):
     self.token = generate_token()
     self.email = '*****@*****.**'
     # User data in format that get_user_data() returns it
     self.get_user_data = {
         'email': self.email,
         'token': self.token,
         'format': 'H',
         'country': 'us',
         'lang': 'en',
         'newsletters': ['slug'],
         'status': 'ok',
     }
Exemplo n.º 4
0
 def test_user_not_in_sf(self, sfdc_mock):
     """A user not found in SFDC should produce an error response."""
     sfdc_mock.get.side_effect = NewsletterException('DANGER!')
     token = generate_token()
     resp = self.client.get('/news/user/{}/'.format(token))
     self.assertEqual(resp.status_code, 400)
     resp_data = json.loads(resp.content)
     self.assertDictEqual(
         resp_data, {
             'status': 'error',
             'desc': 'DANGER!',
             'code': errors.BASKET_UNKNOWN_ERROR,
         })
Exemplo n.º 5
0
 def setUp(self):
     self.token = generate_token()
     self.url = '/news/custom_update_student_ambassadors/%s/' % \
                self.token
     self.data = {'FIRST_NAME': 'Testy',
                  'LAST_NAME': 'McTestface',
                  'EMAIL_ADDRESS': '*****@*****.**',
                  'STUDENTS_CURRENT_STATUS': 'student',
                  'STUDENTS_SCHOOL': 'Testington U',
                  'STUDENTS_GRAD_YEAR': '2014',
                  'STUDENTS_MAJOR': 'computer engineering',
                  'COUNTRY': 'GR',
                  'STUDENTS_CITY': 'Testington',
                  'STUDENTS_ALLOW_SHARE': 'N'}
Exemplo n.º 6
0
def update_fxa_info(email, lang, fxa_id, source_url=None, skip_welcome=False):
    user = get_external_user_data(email=email)
    record = {
        'EMAIL_ADDRESS_': email,
        'FXA_ID': fxa_id,
        'MODIFIED_DATE_': gmttime(),
        'FXA_LANGUAGE_ISO2': lang,
    }
    if user:
        welcome_format = user['format']
        token = user['token']
    else:
        welcome_format = 'H'
        token = generate_token()
        # only want source url for first contact
        record['SOURCE_URL'] = source_url or 'https://accounts.firefox.com'

    record['TOKEN'] = token

    apply_updates(settings.EXACTTARGET_DATA, record)

    if not skip_welcome:
        welcome = mogrify_message_id(FXACCOUNT_WELCOME, lang, welcome_format)
        send_message.delay(welcome, email, token, welcome_format)
Exemplo n.º 7
0
def process_donation(data):
    timestamp = data['timestamp']
    data = data['data']
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    if 'first_name' in data:
        if data.get('first_name'):
            contact_data['first_name'] = data['first_name']
        if data.get('last_name'):
            contact_data['last_name'] = data['last_name']
    elif data.get('last_name'):
        names = data['last_name'].rsplit(None, 1)
        if len(names) == 2:
            first, last = names
        else:
            first, last = '', names[0]
        if first:
            contact_data['first_name'] = first
        if last:
            contact_data['last_name'] = last

    user_data = get_user_data(email=data['email'],
                              extra_fields=['id'])
    if user_data:
        if contact_data and (
                ('first_name' in contact_data and contact_data['first_name'] != user_data['first_name']) or
                ('last_name' in contact_data and contact_data['last_name'] != user_data['last_name'])):
            sfdc.update(user_data, contact_data)
    else:
        contact_data['token'] = generate_token()
        contact_data['email'] = data['email']
        contact_data['record_type'] = settings.DONATE_CONTACT_RECORD_TYPE

        sfdc.add(contact_data)
        # fetch again to get ID
        user_data = get_user_data(email=data.get('email'),
                                  extra_fields=['id'])
        if not user_data:
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask('User not yet available')

    # add opportunity
    donation = {
        'RecordTypeId': settings.DONATE_OPP_RECORD_TYPE,
        'Name': 'Foundation Donation',
        'Donation_Contact__c': user_data['id'],
        'StageName': 'Closed Won',
        'CloseDate': timestamp,
        'Amount': float(data['donation_amount']),
        'Currency__c': data['currency'].upper(),
        'Payment_Source__c': data['service'],
        'PMT_Transaction_ID__c': data['transaction_id'],
        'Payment_Type__c': 'Recurring' if data['recurring'] else 'One-Time',
    }
    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        value = data.get(source_name)
        if value:
            donation[dest_name] = value

    sfdc.opportunity.create(donation)
Exemplo n.º 8
0
def upsert_contact(api_call_type, data, user_data):
    """
    Update or insert (upsert) a contact record in SFDC

    @param int api_call_type: What kind of API call it was. Could be
        SUBSCRIBE, UNSUBSCRIBE, or SET.
    @param dict data: POST data from the form submission
    @param dict user_data: existing contact data from SFDC
    @return: token, created
    """
    update_data = data.copy()
    forced_optin = data.pop('optin', False)
    if 'format' in data:
        update_data['format'] = 'T' if data['format'].upper().startswith('T') else 'H'

    newsletters = parse_newsletters_csv(data.get('newsletters'))

    if user_data:
        cur_newsletters = user_data.get('newsletters', None)
    else:
        cur_newsletters = None

    # check for and remove transactional newsletters
    if api_call_type == SUBSCRIBE:
        all_transactionals = set(get_transactional_message_ids())
        newsletters_set = set(newsletters)
        transactionals = newsletters_set & all_transactionals
        if transactionals:
            newsletters = list(newsletters_set - transactionals)
            send_transactional_messages(update_data, user_data, list(transactionals))
            if not newsletters:
                # no regular newsletters
                return None, None

    # Set the newsletter flags in the record by comparing to their
    # current subscriptions.
    update_data['newsletters'] = parse_newsletters(api_call_type, newsletters, cur_newsletters)

    if api_call_type != UNSUBSCRIBE:
        # 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.
        to_subscribe = [nl for nl, sub in update_data['newsletters'].iteritems() if sub]
        if to_subscribe and not (forced_optin or
                                 (user_data and user_data.get('optin'))):
            exempt_from_confirmation = Newsletter.objects \
                .filter(slug__in=to_subscribe, requires_double_optin=False) \
                .exists()
            if exempt_from_confirmation:
                update_data['optin'] = True

        # record source URL
        nl_map = newsletter_map()
        source_url = update_data.get('source_url')
        email = update_data.get('email')
        if not email:
            email = user_data.get('email') if user_data else None

        if email:
            # send all newsletters whether already subscribed or not
            # bug 1308971
            # if api_call_type == SET this is pref center, so only send new subscriptions
            nl_list = newsletters if api_call_type == SUBSCRIBE else to_subscribe
            for nlid in nl_list:
                record_source_url.delay(email, source_url, nl_map[nlid])

    if user_data is None:
        # no user found. create new one.
        update_data['token'] = generate_token()
        if settings.MAINTENANCE_MODE:
            sfdc_add_update.delay(update_data)
        else:
            # don't catch exceptions here. SalesforceError subclasses will retry.
            sfdc.add(update_data)

        return update_data['token'], True

    if forced_optin and not user_data.get('optin'):
        update_data['optin'] = True

    # they opted out of email before, but are subscribing again
    # clear the optout flag
    if api_call_type != UNSUBSCRIBE and user_data.get('optout'):
        update_data['optout'] = False

    # update record
    if user_data and user_data.get('token'):
        token = user_data['token']
    else:
        token = update_data['token'] = generate_token()

    if settings.MAINTENANCE_MODE:
        sfdc_add_update.delay(update_data, user_data)
    else:
        sfdc.update(user_data, update_data)

    return token, False
Exemplo n.º 9
0
    def check_confirmation(self, user_in_master,
                           user_in_optin, user_in_confirmed,
                           newsletter_with_required_confirmation,
                           newsletter_without_required_confirmation,
                           is_english, type, expected_result, is_optin=False):
        # Generic test routine - given a bunch of initial conditions and
        # an expected result, set up the conditions, make the call,
        # and verify we get the expected result.
        email = "*****@*****.**"
        token = generate_token()

        # What should get_user_data return?
        user = {}

        if user_in_master or user_in_confirmed or user_in_optin:
            user['status'] = 'ok'
            user['email'] = email
            user['format'] = 'T'
            user['token'] = token
            user['master'] = user_in_master
            user['confirmed'] = user_in_master or user_in_confirmed
            user['pending'] = user_in_optin and not user_in_confirmed
            # start with none so whatever we call
            # update_user with is a new subscription
            user['newsletters'] = []
        else:
            # User not in Exact Target at all
            user = None

        # Call data
        data = {}
        if is_english:
            data['lang'] = 'en'
            data['country'] = 'us'
        else:
            data['lang'] = 'fr'
            data['country'] = 'fr'

        # make some newsletters
        nl_required = models.Newsletter.objects.create(
            slug='slug1',
            vendor_id='VENDOR1',
            requires_double_optin=True,
        )
        nl_not_required = models.Newsletter.objects.create(
            slug='slug2',
            vendor_id='VENDOR2',
            requires_double_optin=False,
        )

        newsletters = []
        if newsletter_with_required_confirmation:
            newsletters.append(nl_required.slug)
        if newsletter_without_required_confirmation:
            newsletters.append(nl_not_required.slug)
        data['newsletters'] = ','.join(newsletters)

        # Mock data from ET
        with patch('news.tasks.get_user_data') as get_user_data:
            get_user_data.return_value = user

            # Don't actually call ET
            with patch('news.tasks.apply_updates'):
                with patch('news.tasks.send_welcomes'):
                    with patch('news.tasks.send_confirm_notice'):
                        rc = update_user(data, email, token, type, is_optin)
        self.assertEqual(expected_result, rc)
Exemplo n.º 10
0
def update_user(data, email, token, api_call_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. If None, the token will be
        looked up, and if no token is found, one will be created for the
        given email.
    :param int api_call_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.
    """
    # Get the user's current settings from ET, if any
    user_data = get_user_data(email=email, 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 or generate_token(),
            'master': False,
            'pending': False,
            'confirmed': False,
            'lang': '',
            'status': 'ok',
        }

    token = user_data['token']
    email = user_data['email']

    # 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',
        'first_name': 'FIRST_NAME',
        'last_name': 'LAST_NAME',
    }

    # Optionally add more fields
    for field, et_id in extra_fields.items():
        if field in data:
            record[et_id] = data[field]

    lang = record.get('LANGUAGE_ISO2', '') or ''

    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, api_call_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 api_call_type is SUBSCRIBE and trigger_welcome
    # arg is absent or 'Y'.
    should_send_welcomes = data.get('trigger_welcome', 'Y') == 'Y' and api_call_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
Exemplo n.º 11
0
def update_get_involved(interest_id, lang, name, email, country, email_format,
                        subscribe, message, source_url):
    """Record a users interest and details for contribution."""
    try:
        interest = Interest.objects.get(interest_id=interest_id)
    except Interest.DoesNotExist:
        # invalid request; no need to raise exception and retry
        return

    email_format = 'T' if email_format.upper().startswith('T') else 'H'

    # Get the user's current settings from ET, if any
    user = get_user_data(email=email)

    record = {
        'EMAIL_ADDRESS_': email,
        'MODIFIED_DATE_': gmttime(),
        'LANGUAGE_ISO2': lang,
        'COUNTRY_': country,
        'GET_INVOLVED_FLG': 'Y',
    }
    if user:
        token = user['token']
        if 'get-involved' not in user.get('newsletters', []):
            record['GET_INVOLVED_DATE'] = gmttime()
    else:
        token = generate_token()
        record['EMAIL_FORMAT_'] = email_format
        record['GET_INVOLVED_DATE'] = gmttime()
        # only want source url for first contact
        if source_url:
            record['SOURCE_URL'] = source_url

    record['TOKEN'] = token
    if subscribe:
        # TODO: 'get-involved' not added to ET yet, so can't use it yet.
        # will go in this list when ready.
        newsletters = ['about-mozilla']
        if user:
            cur_newsletters = user.get('newsletters', None)
            if cur_newsletters is not None:
                cur_newsletters = set(cur_newsletters)
        else:
            cur_newsletters = None

        # Set the newsletter flags in the record by comparing to their
        # current subscriptions.
        to_subscribe, _ = parse_newsletters(record, SUBSCRIBE, newsletters, cur_newsletters)
    else:
        to_subscribe = None

    apply_updates(settings.EXACTTARGET_DATA, record)
    apply_updates(settings.EXACTTARGET_INTERESTS, {
        'TOKEN': token,
        'INTEREST': interest_id,
    })
    welcome_id = mogrify_message_id(interest.welcome_id, lang, email_format)
    send_message.delay(welcome_id, email, token, email_format)
    interest.notify_stewards(name, email, lang, message)

    if to_subscribe:
        if not user:
            user = {
                'email': email,
                'token': token,
                'lang': lang,
            }
        send_welcomes(user, to_subscribe, email_format)
Exemplo n.º 12
0
 def setUp(self):
     self.token = generate_token()
     self.url = '/news/custom_update_phonebook/%s/' % self.token