Example #1
0
def sfdc_add_update(update_data, user_data=None):
    # for use with maintenance mode only
    # TODO remove after maintenance is over and queue is processed
    if user_data:
        sfdc.update(user_data, update_data)
        ctms.update(user_data, update_data)
    else:
        ctms_data = update_data.copy()
        ctms_contact = ctms.add(ctms_data)
        if ctms_contact:
            update_data["email_id"] = ctms_contact["email"]["email_id"]

        try:
            sfdc.add(update_data)
        except sfapi.SalesforceMalformedRequest as e:  # noqa
            # possibly a duplicate email. try the update below.
            user_data = get_user_data(email=update_data["email"], extra_fields=["id"])
            if user_data:
                # we have a user, delete generated token and email_id
                # and continue with an update
                update_data.pop("token", None)
                update_data.pop("email_id", None)
                sfdc.update(user_data, update_data)
                ctms.update(user_data, update_data)
            else:
                # still no user, try the add one more time
                ctms_contact = ctms.add(update_data)
                if ctms_contact:
                    update_data["email_id"] = ctms_contact["email"]["email_id"]
                sfdc.add(update_data)
Example #2
0
def confirm_user(token):
    """
    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_lock(token)
    user_data = get_user_data(token=token)

    if user_data is None:
        statsd.incr('news.tasks.confirm_user.confirm_user_not_found')
        return

    if user_data['optin']:
        # already confirmed
        return

    if not ('email' in user_data and user_data['email']):
        raise BasketError('token has no email in ET')

    sfdc.update(user_data, {'optin': True})
Example #3
0
def fxa_email_changed(data):
    ts = data["ts"]
    fxa_id = data["uid"]
    email = data["email"]
    cache_key = "fxa_email_changed:%s" % fxa_id
    prev_ts = float(cache.get(cache_key, 0))
    if prev_ts and prev_ts > ts:
        # message older than our last update for this UID
        return

    # Update SFDC
    user_data = get_user_data(fxa_id=fxa_id, extra_fields=["id"])
    if user_data:
        sfdc.update(user_data, {"fxa_primary_email": email})
    else:
        # FxA record not found, try email
        user_data = get_user_data(email=email, extra_fields=["id"])
        if user_data:
            sfdc.update(user_data, {"fxa_id": fxa_id, "fxa_primary_email": email})
        else:
            # No matching record for Email or FxA ID. Create one.
            sfdc.add({"email": email, "fxa_id": fxa_id, "fxa_primary_email": email})
            statsd.incr("news.tasks.fxa_email_changed.user_not_found")

    sfmc.upsert_row("FXA_EmailUpdated", {"FXA_ID": fxa_id, "NewEmailAddress": email})

    cache.set(cache_key, ts, 7200)  # 2 hr
Example #4
0
def process_subhub_event_customer_created(data):
    """
    Event name: customer.created

    Creates or updates a SFDC customer when a new payment processor/Stripe
    customer is created
    """
    statsd.incr('news.tasks.process_subhub_event.customer_created')

    first, last = split_name(data['name'])
    contact_data = {'fxa_id': data['user_id'], 'payee_id': data['customer_id']}

    user_data = get_user_data(email=data['email'])

    # if user was found in sfdc, see if we should update their name(s)
    if user_data:
        # if current last name is '_', update it
        if user_data['last_name'] == '_':
            contact_data['last_name'] = last

        # if current last name is blank/Null, update it
        if not user_data['first_name']:
            contact_data['first_name'] = first

        sfdc.update(user_data, contact_data)
        statsd.incr('news.tasks.process_subhub_event.customer_created.updated')
    # if no user was found, create new user in sfdc
    else:
        contact_data['email'] = data['email']
        contact_data['first_name'] = first
        contact_data['last_name'] = last

        # create the user in sfdc
        statsd.incr('news.tasks.process_subhub_event.customer_created.created')
        sfdc.add(contact_data)
Example #5
0
def update_user_meta(token, data):
    """Update a user's metadata, not newsletters"""
    sfdc.update({"token": token}, data)
    try:
        ctms.update_by_alt_id("token", token, data)
    except CTMSNotFoundByAltIDError:
        if not settings.SFDC_ENABLED:
            raise
Example #6
0
def update_user_meta(token, data):
    """Update a user's metadata, not newsletters"""
    sfdc.update({"token": token}, data)
    try:
        ctms.update_by_alt_id("token", token, data)
    except CTMSNotFoundByAltIDError:
        # TODO: raise this exception when CTMS is primary data source
        pass
Example #7
0
def update_custom_unsub(token, reason):
    """Record a user's custom unsubscribe reason."""
    get_lock(token)
    try:
        sfdc.update({'token': token}, {'reason': reason})
    except sfapi.SalesforceMalformedRequest:
        # likely the record can't be found. nothing to do.
        pass
Example #8
0
def process_petition_signature(data):
    """
    Add petition signature to SFDC
    """
    data = data['form']
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    contact_data.update(
        {k: data[k]
         for k in PETITION_CONTACT_FIELDS if data.get(k)})

    user_data = get_user_data(email=data['email'], extra_fields=['id'])
    if user_data:
        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')

    if data.get('email_subscription', False):
        upsert_user.delay(
            SUBSCRIBE, {
                'token': user_data['token'],
                'lang': data.get('lang', 'en-US'),
                'newsletters': 'mozilla-foundation',
                'source_url': data['source_url'],
            })

    campaign_member = {
        'CampaignId': data['campaign_id'],
        'ContactId': user_data['id'],
        'Full_URL__c': data['source_url'],
        'Status': 'Signed',
    }
    comments = data.get('comments')
    if comments:
        campaign_member['Petition_Comments__c'] = comments[:500]

    metadata = data.get('metadata')
    if metadata:
        campaign_member['Petition_Flex__c'] = json.dumps(metadata)[:500]

    try:
        sfdc.campaign_member.create(campaign_member)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Example #9
0
def amo_check_user_for_deletion(user_id):
    """If a user has no addons their AMO info should be removed"""
    addons = sfdc.sf.query(
        sfapi.format_soql(
            "SELECT Id FROM DevAddOn__c WHERE AMO_Contact_ID__c = {contact_id} LIMIT 1",
            contact_id=user_id,
        ), )
    if not addons["records"]:
        sfdc.update({"id": user_id}, {"amo_id": None, "amo_user": False})
Example #10
0
def process_petition_signature(data):
    """
    Add petition signature to SFDC
    """
    data = data['form']
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    contact_data.update({k: data[k] for k in PETITION_CONTACT_FIELDS if data.get(k)})

    user_data = get_user_data(email=data['email'],
                              extra_fields=['id'])
    if user_data:
        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')

    if data.get('email_subscription', False):
        upsert_user.delay(SUBSCRIBE, {
            'token': user_data['token'],
            'lang': 'en-US',
            'newsletters': 'mozilla-foundation',
            'source_url': data['source_url'],
        })

    campaign_member = {
        'CampaignId': data['campaign_id'],
        'ContactId': user_data['id'],
        'Full_URL__c': data['source_url'],
        'Status': 'Signed',
    }
    comments = data.get('comments')
    if comments:
        campaign_member['Petition_Comments__c'] = comments[:500]

    metadata = data.get('metadata')
    if metadata:
        campaign_member['Petition_Flex__c'] = json.dumps(metadata)[:500]

    try:
        sfdc.campaign_member.create(campaign_member)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Example #11
0
def update_custom_unsub(token, reason):
    """Record a user's custom unsubscribe reason."""
    get_lock(token)
    try:
        sfdc.update({"token": token}, {"reason": reason})
    except sfapi.SalesforceMalformedRequest:
        # likely the record can't be found. nothing to do.
        return

    try:
        ctms.update_by_alt_id("token", token, {"reason": reason})
    except CTMSNotFoundByAltIDError:
        # No record found for that token, nothing to do.
        pass
Example #12
0
def process_subhub_event_subscription_cancel(data):
    """
    Event name: customer.subscription_cancelled or customer.deleted
    """
    statsd.incr('news.tasks.process_subhub_event.subscription_cancel')
    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event_subscription_cancel.user_not_found'
        )
        raise RetryTask('Could not find user. Try again.')

    nickname = data['nickname']
    if isinstance(nickname, list):
        nickname = nickname[0]

    sfdc.opportunity.create({
        'Amount':
        cents_to_dollars(data['plan_amount']),
        'Billing_Cycle_End__c':
        iso_format_unix_timestamp(data['current_period_end']),
        'Billing_Cycle_Start__c':
        iso_format_unix_timestamp(data['current_period_start']),
        'CloseDate':
        iso_format_unix_timestamp(data.get('cancel_at', time())),
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Name':
        'Subscription Services',
        'Payment_Source__c':
        'Stripe',
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        nickname,
        'StageName':
        SUB_STAGE_NAMES[data['event_type']],
    })

    if data['event_type'] == 'customer.deleted':
        sfdc.update(user_data, {'fxa_deleted': True})
Example #13
0
def update_custom_unsub(token, reason):
    """Record a user's custom unsubscribe reason."""
    get_lock(token)
    try:
        sfdc.update({'token': token}, {'reason': reason})
    except sfapi.SalesforceMalformedRequest:
        # likely the record can't be found. try the DoI DE.
        user = get_sfmc_doi_user(token)
        if user and user.get('email'):
            get_lock(user['email'])
            user['reason'] = reason
            try:
                sfdc.add(user)
            except sfapi.SalesforceMalformedRequest:
                # probably already know the email address
                sfdc.update({'email': user['email']}, user)
Example #14
0
def update_custom_unsub(token, reason):
    """Record a user's custom unsubscribe reason."""
    get_lock(token)
    try:
        sfdc.update({'token': token}, {'reason': reason})
    except sfapi.SalesforceMalformedRequest:
        # likely the record can't be found. try the DoI DE.
        user = get_sfmc_doi_user(token)
        if user and user.get('email'):
            get_lock(user['email'])
            user['reason'] = reason
            try:
                sfdc.add(user)
            except sfapi.SalesforceMalformedRequest:
                # probably already know the email address
                sfdc.update({'email': user['email']}, user)
Example #15
0
def record_common_voice_update(data):
    # do not change the sent data in place. A retry will use the changed data.
    dcopy = data.copy()
    email = dcopy.pop("email")
    user_data = get_user_data(email=email, extra_fields=["id"])
    new_data = {
        "source_url": "https://voice.mozilla.org",
        "newsletters": [settings.COMMON_VOICE_NEWSLETTER],
    }
    for k, v in dcopy.items():
        new_data["cv_" + k] = v

    if user_data:
        sfdc.update(user_data, new_data)
    else:
        new_data.update({"email": email, "token": generate_token()})
        sfdc.add(new_data)
Example #16
0
def upsert_amo_user_data(data, user_sync=False):
    """
    Update AMO user data in the SFDC contact, or create a contact.
    Return the Contact data (the contact ID at a minimum).

    :param data: dict of amo user data
    :param user_sync: bool True if this is a User Sync request
    :return: dict of SFDC contact data
    """
    data = data.copy()
    fxa_id = data.pop("fxa_id", None)
    amo_id = data.pop("id", None)
    user = None

    # records can come in with no "id" or "fxa_id" field
    if amo_id:
        user = get_user_data(amo_id=amo_id,
                             extra_fields=["id", "amo_id", "fxa_id"])
        if not user and fxa_id:
            # Try to find user with fxa_id
            user = get_user_data(fxa_id=fxa_id,
                                 extra_fields=["id", "amo_id", "fxa_id"])

    if not user:
        # Cannot find user with FxA ID or AMO ID, ignore the update
        return None

    if user_sync and not user["amo_id"]:
        # do not update user as AMO User unless it comes from an AddonSync
        return None

    amo_deleted = data.pop("deleted", False)
    amo_data = {f"amo_{k}": v for k, v in data.items() if v}
    amo_data["amo_id"] = amo_id
    amo_data["amo_deleted"] = amo_deleted
    if not user_sync:
        # only ensure this is true if this is from an addon sync
        amo_data["amo_user"] = True

    if amo_deleted or fxa_id is None:
        amo_data["amo_id"] = None

    sfdc.update(user, amo_data)
    ctms.update(user, amo_data)
    return user
Example #17
0
def record_common_voice_goals(data):
    email = data.pop('email')
    user_data = get_user_data(email=email, extra_fields=['id'])
    new_data = {
        'source_url': 'https://voice.mozilla.org',
        'newsletters': [settings.COMMON_VOICE_NEWSLETTER],
    }
    for k, v in data.items():
        new_data['cv_' + k] = v

    if user_data:
        sfdc.update(user_data, new_data)
    else:
        new_data.update({
            'email': email,
            'token': generate_token(),
        })
        sfdc.add(new_data)
Example #18
0
def sfdc_add_update(update_data, user_data=None):
    # for use with maintenance mode only
    # TODO remove after maintenance is over and queue is processed
    if user_data:
        sfdc.update(user_data, update_data)
    else:
        try:
            sfdc.add(update_data)
        except sfapi.SalesforceMalformedRequest as e:  # noqa
            # possibly a duplicate email. try the update below.
            user_data = get_user_data(email=update_data['email'], extra_fields=['id'])
            if user_data:
                # we have a user, delete generated token
                # and continue with an update
                update_data.pop('token', None)
                sfdc.update(user_data, update_data)
            else:
                # still no user, try the add one more time
                sfdc.add(update_data)
Example #19
0
def sfdc_add_update(update_data, user_data=None):
    # for use with maintenance mode only
    # TODO remove after maintenance is over and queue is processed
    if user_data:
        sfdc.update(user_data, update_data)
    else:
        try:
            sfdc.add(update_data)
        except sfapi.SalesforceMalformedRequest as e:  # noqa
            # possibly a duplicate email. try the update below.
            user_data = get_user_data(email=update_data['email'], extra_fields=['id'])
            if user_data:
                # we have a user, delete generated token
                # and continue with an update
                update_data.pop('token', None)
                sfdc.update(user_data, update_data)
            else:
                # still no user, try the add one more time
                sfdc.add(update_data)
Example #20
0
def fxa_email_changed(data):
    ts = data["ts"]
    fxa_id = data["uid"]
    email = data["email"]
    cache_key = "fxa_email_changed:%s" % fxa_id
    prev_ts = float(cache.get(cache_key, 0))
    if prev_ts and prev_ts > ts:
        # message older than our last update for this UID
        return

    # Update SFDC / CTMS
    user_data = get_user_data(fxa_id=fxa_id, extra_fields=["id"])
    if user_data:
        sfdc.update(user_data, {"fxa_primary_email": email})
        ctms.update(user_data, {"fxa_primary_email": email})
    else:
        # FxA record not found, try email
        user_data = get_user_data(email=email, extra_fields=["id"])
        if user_data:
            sfdc.update(user_data, {
                "fxa_id": fxa_id,
                "fxa_primary_email": email
            })
            ctms.update(user_data, {
                "fxa_id": fxa_id,
                "fxa_primary_email": email
            })
        else:
            # No matching record for Email or FxA ID. Create one.
            data = {
                "email": email,
                "token": generate_token(),
                "fxa_id": fxa_id,
                "fxa_primary_email": email,
            }
            ctms_data = data.copy()
            contact = ctms.add(ctms_data)
            if contact:
                data["email_id"] = contact["email"]["email_id"]
            sfdc.add(data)
            statsd.incr("news.tasks.fxa_email_changed.user_not_found")

    cache.set(cache_key, ts, 7200)  # 2 hr
Example #21
0
def record_common_voice_goals(data):
    # do not change the sent data in place. A retry will use the changed data.
    dcopy = data.copy()
    email = dcopy.pop('email')
    user_data = get_user_data(email=email, extra_fields=['id'])
    new_data = {
        'source_url': 'https://voice.mozilla.org',
        'newsletters': [settings.COMMON_VOICE_NEWSLETTER],
    }
    for k, v in dcopy.items():
        new_data['cv_' + k] = v

    if user_data:
        sfdc.update(user_data, new_data)
    else:
        new_data.update({
            'email': email,
            'token': generate_token(),
        })
        sfdc.add(new_data)
Example #22
0
def confirm_user(token):
    """
    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_lock(token)
    user_data = get_user_data(token=token)

    if user_data is None:
        user = get_sfmc_doi_user(token)
        if user and user.get('email'):
            get_lock(user['email'])
            user['optin'] = True
            try:
                sfdc.add(user)
            except sfapi.SalesforceMalformedRequest:
                # probably already know the email address
                sfdc.update({'email': user['email']}, user)
            statsd.incr('news.tasks.confirm_user.moved_from_sfmc')
        else:
            statsd.incr('news.tasks.confirm_user.confirm_user_not_found')

        return

    if user_data['optin']:
        # already confirmed
        return

    if not ('email' in user_data and user_data['email']):
        raise BasketError('token has no email in ET')

    sfdc.update(user_data, {'optin': True})
Example #23
0
def confirm_user(token):
    """
    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_lock(token)
    user_data = get_user_data(token=token)

    if user_data is None:
        user = get_sfmc_doi_user(token)
        if user and user.get('email'):
            get_lock(user['email'])
            user['optin'] = True
            try:
                sfdc.add(user)
            except sfapi.SalesforceMalformedRequest:
                # probably already know the email address
                sfdc.update({'email': user['email']}, user)
            statsd.incr('news.tasks.confirm_user.moved_from_sfmc')
        else:
            statsd.incr('news.tasks.confirm_user.confirm_user_not_found')

        return

    if user_data['optin']:
        # already confirmed
        return

    if not ('email' in user_data and user_data['email']):
        raise BasketError('token has no email in ET')

    sfdc.update(user_data, {'optin': True})
Example #24
0
def get_fxa_user_data(fxa_id, email):
    """Return a user data dict, just like `get_user_data` below, but ensure we have a good FxA contact

    First look for a user by FxA ID. If we get a user, and the email matches what was passed in, return it.
    If the email doesn't match, set the first user's FxA_ID to "DUPE:<fxa_id>" so that we don't run into dupe
    issues, and set "fxa_deleted" to True. Then look up a user with the email address and return that or None.
    """
    user_data = None
    # try getting user data with the fxa_id first
    user_data_fxa = get_user_data(fxa_id=fxa_id, extra_fields=["id"])
    if user_data_fxa:
        user_data = user_data_fxa
        # If email doesn't match, update FxA primary email field with the new email.
        if user_data_fxa["email"] != email:
            sfdc.update(user_data_fxa, {"fxa_primary_email": email})

    # if we still don't have user data try again with email this time
    if not user_data:
        user_data = get_user_data(email=email, extra_fields=["id"])

    return user_data
Example #25
0
def upsert_amo_user_data(data):
    """
    Update AMO user data in the SFDC contact, or create a contact.
    Return the Contact data (the contact ID at a minimum).

    :param data: dict of amo user data
    :return: dict of SFDC contact data
    """
    fxa_id = data.pop("fxa_id")
    amo_id = data.pop("id")

    user = get_user_data(amo_id=amo_id, extra_fields=["id", "amo_id", "fxa_id"])
    if not user:
        # Try to find user with fxa_id
        user = get_user_data(fxa_id=fxa_id, extra_fields=["id", "amo_id", "fxa_id"])

    if not user:
        # Cannot find user with FxA ID or AMO ID, ignore the update
        return None

    amo_deleted = data.pop("deleted", False)
    amo_data = {f"amo_{k}": v for k, v in data.items() if v}
    amo_data["amo_user"] = True
    amo_data["amo_id"] = amo_id
    amo_data["amo_deleted"] = amo_deleted

    if amo_deleted:
        if fxa_id is None:
            # Deleted user, we don't want do keep linking that AMO account with
            # that FxA account in Salesforce, they might re-create a new AMO
            # account from their previous FxA account.
            amo_data["amo_id"] = None
    else:
        if fxa_id is None:
            # User takeover protection, we don't want do keep linking that AMO
            # account with that FxA account in Salesforce
            amo_data["amo_id"] = None

    sfdc.update(user, amo_data)
    return user
Example #26
0
def upsert_amo_user_data(data):
    """
    Update AMO user data in the SFDC contact, or create a contact.
    Return the Contact data (the contact ID at a minimum).

    :param data: dict of amo user data
    :return: dict of SFDC contact data
    """
    email = data.pop('email')
    amo_id = data.pop('id')
    amo_deleted = data.pop('deleted', False)
    amo_data = {f'amo_{k}': v for k, v in data.items() if v}
    amo_data['amo_user'] = not amo_deleted
    user = get_user_data(amo_id=amo_id, extra_fields=['id', 'amo_id'])
    if user:
        sfdc.update(user, amo_data)
        return user

    # include the ID in update or add since we couldn't find
    # the user with this ID above
    amo_data['amo_id'] = amo_id
    user = get_user_data(email=email, extra_fields=['id'])
    if user:
        sfdc.update(user, amo_data)
        # need amo_id for linking addons and authors
        user['amo_id'] = amo_id
        return user

    amo_data['email'] = email
    amo_data['source_url'] = 'https://addons.mozilla.org/'
    # returns only the new user ID in a dict, but that will work
    # when passed to e.g. `sfdc.update()`
    user = sfdc.add(amo_data)
    # need amo_id for linking addons and authors
    user['amo_id'] = amo_id
    return user
Example #27
0
def process_petition_signature(data):
    """
    Add petition signature to CTMS / SFDC

    If SFDC is enabled, a campaign member record is created.
    """
    data = data["form"]
    get_lock(data["email"])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {
        "_set_subscriber": False,  # SFDC: leave the "subscriber" flag alone
        "mofo_relevant": True,  # CTMS: set contact as MoFo relevant
    }
    contact_data.update({k: data[k] for k in PETITION_CONTACT_FIELDS if data.get(k)})

    user_data = get_user_data(email=data["email"], extra_fields=["id"])
    if user_data:
        sfdc.update(user_data, contact_data)
        ctms_data = contact_data.copy()
        del ctms_data["_set_subscriber"]
        ctms.update(user_data, ctms_data)
    else:
        contact_data["token"] = generate_token()
        contact_data["email"] = data["email"]
        ctms_data = contact_data.copy()
        contact_data["record_type"] = settings.DONATE_CONTACT_RECORD_TYPE

        del ctms_data["_set_subscriber"]
        ctms_data["mofo_relevant"] = True
        contact = ctms.add(ctms_data)
        if contact:
            contact_data["email_id"] = contact["email"]["email_id"]

        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")

    if data.get("email_subscription", False):
        upsert_user.delay(
            SUBSCRIBE,
            {
                "token": user_data["token"],
                "lang": data.get("lang", "en-US"),
                "newsletters": "mozilla-foundation",
                "source_url": data["source_url"],
            },
        )

    if not settings.SFDC_ENABLED:
        return

    campaign_id = data["campaign_id"]
    # Fix a specific issue with a specific campaign where the ID was entered without
    # the leading 7
    if len(campaign_id) == 17 and not campaign_id.startswith("7"):
        campaign_id = f"7{campaign_id}"

    campaign_member = {
        "CampaignId": campaign_id,
        "ContactId": user_data["id"],
        "Full_URL__c": data["source_url"],
        "Status": "Signed",
    }
    comments = data.get("comments")
    if comments:
        campaign_member["Petition_Comments__c"] = comments[:500]

    metadata = data.get("metadata")
    if metadata:
        campaign_member["Petition_Flex__c"] = json.dumps(metadata)[:500]

    try:
        sfdc.campaign_member.create(campaign_member)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get("errorCode") == "DUPLICATE_VALUE":
            # already in the system, ignore
            pass
        else:
            raise
Example #28
0
def process_donation(data):
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    # do "or ''" because data can contain None values
    first_name = (data.get('first_name') or '').strip()
    last_name = (data.get('last_name') or '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif 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',
        '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',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if source_name in data:
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Example #29
0
def fxa_delete(data):
    sfmc.upsert_row("FXA_Deleted", {"FXA_ID": data["uid"]})
    user_data = get_user_data(fxa_id=data["uid"], extra_fields=["id"])
    if user_data:
        sfdc.update(user_data, {"fxa_deleted": True})
Example #30
0
def process_donation(data):
    if 'data' in data:
        # here for old messages
        # TODO remove in a subsequent deployment
        data = data['data']
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    first_name = data.get('first_name', '').strip()
    last_name = data.get('last_name', '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif 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',
        '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',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Example #31
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'].items() 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:
                if nlid in nl_map:
                    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
Example #32
0
def update_user_meta(token, data):
    """Update a user's metadata, not newsletters"""
    sfdc.update({'token': token}, data)
Example #33
0
def fxa_delete(data):
    sfmc.upsert_row('FXA_Deleted', {'FXA_ID': data['uid']})
    user_data = get_user_data(fxa_id=data['uid'], extra_fields=['id'])
    if user_data:
        sfdc.update(user_data, {'fxa_deleted': True})
Example #34
0
def process_donation(data):
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    # do "or ''" because data can contain None values
    first_name = (data.get('first_name') or '').strip()
    last_name = (data.get('last_name') or '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif 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

        # returns a dict with the new ID but no other user data, but that's enough here
        user_data = sfdc.add(contact_data)
        if not user_data.get('id'):
            # 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',
        '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',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if data.get(source_name):
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Example #35
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:
                if nlid in nl_map:
                    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
Example #36
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_acoustic_tx_messages(
                data["email"], data.get("lang", "en-US"), 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,
    )
    send_confirm = False

    if api_call_type != UNSUBSCRIBE:
        # Check for newsletter-specific user updates
        to_subscribe_slugs = [
            nl for nl, sub in update_data["newsletters"].items() if sub
        ]
        check_optin = not (forced_optin or (user_data and user_data.get("optin")))
        check_mofo = not (user_data and user_data.get("mofo_relevant"))
        if to_subscribe_slugs and (check_optin or check_mofo):
            to_subscribe = Newsletter.objects.filter(slug__in=to_subscribe_slugs)

            # Are they subscribing to any newsletters that require confirmation?
            # If none require confirmation, user goes straight to confirmed (optin)
            # Otherwise, prepare to send a fx or moz confirmation
            if check_optin:
                exempt_from_confirmation = any(
                    [not o.requires_double_optin for o in to_subscribe],
                )
                if exempt_from_confirmation:
                    update_data["optin"] = True
                else:
                    send_fx_confirm = all([o.firefox_confirm for o in to_subscribe])
                    send_confirm = "fx" if send_fx_confirm else "moz"

            # Update a user to MoFo-relevant if they subscribed to a MoFo newsletters
            if check_mofo:
                if any([ns.is_mofo for ns in to_subscribe]):
                    update_data["mofo_relevant"] = True

    if user_data is None:
        # no user found. create new one.
        token = update_data["token"] = generate_token()
        if settings.MAINTENANCE_MODE:
            sfdc_add_update.delay(update_data)
        else:
            ctms_data = update_data.copy()
            ctms_contact = ctms.add(ctms_data)
            if ctms_contact:
                # Successfully added to CTMS, send email_id to SFDC
                update_data["email_id"] = ctms_contact["email"]["email_id"]

            # don't catch exceptions here. SalesforceError subclasses will retry.
            sfdc.add(update_data)

        if send_confirm and settings.SEND_CONFIRM_MESSAGES:
            send_confirm_message.delay(
                data["email"], token, data.get("lang", "en-US"), send_confirm,
            )

        return 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)
        ctms.update(user_data, update_data)

    if send_confirm and settings.SEND_CONFIRM_MESSAGES:
        send_confirm_message.delay(
            user_data["email"],
            token,
            update_data.get("lang", user_data.get("lang", "en-US")),
            send_confirm,
        )

    return token, False
Example #37
0
def process_donation(data):
    get_lock(data["email"])
    contact_data = {
        "_set_subscriber": False,  # SFDC, leave "subscriber" flag alone
        "mofo_relevant": True,  # CTMS, set a MoFo relevant contact
    }
    # do "or ''" because data can contain None values
    first_name = (data.get("first_name") or "").strip()
    last_name = (data.get("last_name") or "").strip()
    if first_name and last_name:
        contact_data["first_name"] = first_name
        contact_data["last_name"] = last_name
    elif first_name:
        contact_data["first_name"] = first_name
    elif 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)
            ctms_data = contact_data.copy()
            del ctms_data["_set_subscriber"]
            ctms.update(user_data, ctms_data)
    else:
        contact_data["token"] = generate_token()
        contact_data["email"] = data["email"]
        contact_data["record_type"] = settings.DONATE_CONTACT_RECORD_TYPE

        ctms_data = contact_data.copy()
        del ctms_data["_set_subscriber"]
        del ctms_data["record_type"]
        contact = ctms.add(ctms_data)
        if contact:
            contact_data["email_id"] = contact["email"]["email_id"]

        if not settings.SFDC_ENABLED:
            return

        # returns a dict with the new ID but no other user data, but that's enough here
        user_data = sfdc.add(contact_data)
        if not user_data.get("id"):
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask("User not yet available")

    if not settings.SFDC_ENABLED:
        return

    # add opportunity
    donation = {
        "RecordTypeId": settings.DONATE_OPP_RECORD_TYPE,
        "Name": "Foundation Donation",
        "Donation_Contact__c": user_data["id"],
        "StageName": "Closed Won",
        "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",
    }
    # https://github.com/mozmeao/basket/issues/364
    if "campaign_id" in data:
        donation["CampaignId"] = data["campaign_id"]

    # this is a unix timestamp in ms since epoc
    timestamp = data.get("created")
    if timestamp:
        donation["CloseDate"] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if data.get(source_name):
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get("errorCode") == "DUPLICATE_VALUE":
            # already in the system, ignore
            pass
        else:
            raise
Example #38
0
def update_user_meta(token, data):
    """Update a user's metadata, not newsletters"""
    sfdc.update({'token': token}, data)