class LeanplumApi::API

Constants

EXPORT_FINISHED
EXPORT_PENDING

Data export related constants

EXPORT_RUNNING
SET_DEVICE_ATTRIBUTES
SET_USER_ATTRIBUTES

API Command Constants

TRACK

Public Class Methods

new() click to toggle source
# File lib/leanplum_api/api.rb, line 13
def initialize
  fail 'LeanplumApi not configured yet!' unless LeanplumApi.configuration
end

Public Instance Methods

delete_user(user_id, full_erasure = false) click to toggle source
# File lib/leanplum_api/api.rb, line 87
def delete_user(user_id, full_erasure = false)
  development_connection.get(action: 'deleteUser', userId: user_id, fullErasure: full_erasure).first['vars']
end
export_user(user_id) click to toggle source
# File lib/leanplum_api/api.rb, line 57
def export_user(user_id)
  response = data_export_connection.get(action: 'exportUser', userId: user_id).first
  fail ResourceNotFoundError, "User #{user_id} not found" unless response['events'] || response['userAttributes']
  response
end
get_ab_test(ab_test_id) click to toggle source
# File lib/leanplum_api/api.rb, line 67
def get_ab_test(ab_test_id)
  content_read_only_connection.get(action: 'getAbTest', id: ab_test_id).first['abTest']
end
get_ab_tests(only_recent = false) click to toggle source
# File lib/leanplum_api/api.rb, line 63
def get_ab_tests(only_recent = false)
  content_read_only_connection.get(action: 'getAbTests', recent: only_recent).first['abTests']
end
get_message(message_id) click to toggle source
# File lib/leanplum_api/api.rb, line 79
def get_message(message_id)
  content_read_only_connection.get(action: 'getMessage', id: message_id).first['message']
end
get_messages(only_recent = false) click to toggle source
# File lib/leanplum_api/api.rb, line 75
def get_messages(only_recent = false)
  content_read_only_connection.get(action: 'getMessages', recent: only_recent).first['messages']
end
get_variant(variant_id) click to toggle source
# File lib/leanplum_api/api.rb, line 71
def get_variant(variant_id)
  content_read_only_connection.get(action: 'getVariant', id: variant_id).first['variant']
end
get_vars(user_id) click to toggle source
# File lib/leanplum_api/api.rb, line 83
def get_vars(user_id)
  production_connection.get(action: 'getVars', userId: user_id).first['vars']
end
import_csv(bucket, file_path, user_attributes = true) click to toggle source
# File lib/leanplum_api/api.rb, line 100
def import_csv(bucket, file_path, user_attributes = true)
  request_data = {
    createJob: true,
    defaultAction: user_attributes ? SET_USER_ATTRIBUTES : SET_DEVICE_ATTRIBUTES,
    gcsBucket: bucket,
    file: file_path
  }
  development_connection.multi_dev(request_data)
end
reset_anomalous_users(user_ids) click to toggle source

If you pass old events OR users with old date attributes (e.g. create_date for an old user), Leanplum wil mark them 'anomalous' and exclude them from your data set. Calling this method after you pass old events will fix that for all events for the specified user_id.

# File lib/leanplum_api/api.rb, line 94
def reset_anomalous_users(user_ids)
  user_ids = Array.wrap(user_ids)
  request_data = user_ids.map { |user_id| { action: SET_USER_ATTRIBUTES, resetAnomalies: true, userId: user_id } }
  development_connection.multi(request_data)
end
set_device_attributes(device_attributes, options = {}) click to toggle source
# File lib/leanplum_api/api.rb, line 21
def set_device_attributes(device_attributes, options = {})
  track_multi(device_attributes: device_attributes, options: options)
end
set_user_attributes(user_attributes, options = {}) click to toggle source
# File lib/leanplum_api/api.rb, line 17
def set_user_attributes(user_attributes, options = {})
  track_multi(user_attributes: user_attributes, options: options)
end
track_events(events, options = {}) click to toggle source
# File lib/leanplum_api/api.rb, line 25
def track_events(events, options = {})
  track_multi(events: events, options: options)
end
track_multi(events: nil, user_attributes: nil, device_attributes: nil, options: {}) click to toggle source

This method is for tracking events and/or updating user and/or device attributes at the same time, batched together like leanplum recommends. Set the :force_anomalous_override option to catch warnings from leanplum about anomalous events and force them to not be considered anomalous.

# File lib/leanplum_api/api.rb, line 33
def track_multi(events: nil, user_attributes: nil, device_attributes: nil, options: {})
  events = Array.wrap(events)

  request_data = events.map { |h| build_event_attributes_hash(h.dup, options) } +
                 Array.wrap(user_attributes).map { |h| build_user_attributes_hash(h.dup) } +
                 Array.wrap(device_attributes).map { |h| build_device_attributes_hash(h.dup) }

  response = production_connection.multi(request_data)
  force_anomalous_override(response, events) if options[:force_anomalous_override]

  response
end
user_attributes(user_id) click to toggle source
# File lib/leanplum_api/api.rb, line 46
def user_attributes(user_id)
  # Leanplum returns strings instead of booleans
  export_user(user_id)['userAttributes']
    .map { |k, v| [k, v.to_s =~ /\A(true|false)\z/i ? eval(v.downcase) : v] }
    .to_h
end
user_events(user_id) click to toggle source
# File lib/leanplum_api/api.rb, line 53
def user_events(user_id)
  export_user(user_id)['events']
end

Private Instance Methods

build_device_attributes_hash(device_hash) click to toggle source

build a user attributes hash @param [Hash] device_hash device attributes to set into LP device

# File lib/leanplum_api/api.rb, line 161
def build_device_attributes_hash(device_hash)
  device_hash = fix_iso8601(device_hash)
  extract_user_id_or_device_id_hash!(device_hash).merge(
    action: SET_DEVICE_ATTRIBUTES,
    deviceAttributes: device_hash
  )
end
build_event_attributes_hash(event_hash, options = {}) click to toggle source

Events have a :user_id or :device id, a name (:event) and an optional time (:time) Use the :allow_offline option to send events without creating a new session

# File lib/leanplum_api/api.rb, line 171
def build_event_attributes_hash(event_hash, options = {})
  event_name = event_hash.delete(:event)
  fail ":event key not present in #{event_hash}" unless event_name

  event = { action: TRACK, event: event_name }.merge(extract_user_id_or_device_id_hash!(event_hash))
  event.merge!(time: event_hash.delete(:time).strftime('%s').to_i) if event_hash[:time]
  event.merge!(info: event_hash.delete(:info)) if event_hash[:info]
  event.merge!(currencyCode: event_hash.delete(:currency_code)) if event_hash[:currency_code]
  event.merge!(value: event_hash.delete(:value).to_f) if event_hash[:value]
  event.merge!(allowOffline: true) if options[:allow_offline]

  event_hash.keys.size > 0 ? event.merge(params: event_hash.symbolize_keys ) : event
end
build_user_attributes_hash(user_hash) click to toggle source

build a user attributes hash @param [Hash] user_hash user attributes to set into LP user

# File lib/leanplum_api/api.rb, line 145
def build_user_attributes_hash(user_hash)
  user_attr_hash = extract_user_id_or_device_id_hash!(user_hash)
  user_attr_hash[:action] = SET_USER_ATTRIBUTES
  user_attr_hash[:devices] = user_hash.delete(:devices) if user_hash.key?(:devices)

  if user_hash.key?(:events)
    user_attr_hash[:events] = user_hash.delete(:events)
    user_attr_hash[:events].each { |k, v| user_attr_hash[:events][k] = fix_seconds_since_epoch(v) }
  end

  user_attr_hash[:userAttributes] = fix_iso8601(user_hash)
  user_attr_hash
end
content_read_only_connection() click to toggle source

Only instantiated for ContentReadOnly calls (AB tests)

# File lib/leanplum_api/api.rb, line 124
def content_read_only_connection
  fail 'content_read_only_key not configured!' unless LeanplumApi.configuration.content_read_only_key
  @content_read_only ||= Connection.new(LeanplumApi.configuration.content_read_only_key)
end
data_export_connection() click to toggle source

Only instantiated for data export endpoint calls

# File lib/leanplum_api/api.rb, line 118
def data_export_connection
  fail 'data_export_key not configured!' unless LeanplumApi.configuration.data_export_key
  @data_export ||= Connection.new(LeanplumApi.configuration.data_export_key)
end
development_connection() click to toggle source
# File lib/leanplum_api/api.rb, line 129
def development_connection
  fail 'development_key not configured!' unless LeanplumApi.configuration.development_key
  @development ||= Connection.new(LeanplumApi.configuration.development_key)
end
extract_user_id_or_device_id_hash!(hash) click to toggle source

Deletes the user_id and device_id key/value pairs from the hash parameter.

# File lib/leanplum_api/api.rb, line 135
def extract_user_id_or_device_id_hash!(hash)
  user_id = hash.delete(:user_id) || hash.delete(:userId)
  device_id = hash.delete(:device_id) || hash.delete(:deviceId)
  fail "No device_id or user_id in hash #{hash}" unless user_id || device_id

  user_id ? { userId: user_id } : { deviceId: device_id }
end
fix_iso8601(attr_hash) click to toggle source

As of 2015-10 Leanplum supports ISO8601 date & time strings as user attributes.

# File lib/leanplum_api/api.rb, line 211
def fix_iso8601(attr_hash)
  Hash[attr_hash.map { |k, v| [k, (is_date_or_time?(v) ? v.iso8601 : v)] }]
end
fix_seconds_since_epoch(attr_hash) click to toggle source
# File lib/leanplum_api/api.rb, line 215
def fix_seconds_since_epoch(attr_hash)
  Hash[attr_hash.map { |k, v| [k, (is_date_or_time?(v) ? v.strftime('%s').to_i : v)] }]
end
force_anomalous_override(responses, events) click to toggle source

Leanplum's engineering team likes to break their API and or change stuff without warning (often) and has no idea what “versioning” actually means, so we just reset everyone on any type of warning.

# File lib/leanplum_api/api.rb, line 187
def force_anomalous_override(responses, events)
  user_ids_to_reset = []

  responses.each_with_index do |indicator, i|
    # This condition should be:
    # if indicator['warning'] && indicator['warning']['message'] =~ /Past event detected/i
    # but it has to be:
    if indicator['warning']
      # Leanplum does not return their warnings in order!!!  So we just have
      # to reset everyone who had any events.  This is what the code should be:
      # user_ids_to_reset << request_data[i]['userId']

      # This is what it has to be:
      user_ids_to_reset = events.map { |e| e[:user_id] }.uniq
    end
  end

  unless user_ids_to_reset.empty?
    LeanplumApi.configuration.logger.debug("Resetting anomalous user ids: #{user_ids_to_reset}")
    reset_anomalous_users(user_ids_to_reset)
  end
end
is_date_or_time?(obj) click to toggle source
# File lib/leanplum_api/api.rb, line 219
def is_date_or_time?(obj)
  obj.is_a?(Date) || obj.is_a?(Time) || obj.is_a?(DateTime)
end
production_connection() click to toggle source
# File lib/leanplum_api/api.rb, line 112
def production_connection
  fail 'production_key not configured!' unless LeanplumApi.configuration.production_key
  @production ||= Connection.new(LeanplumApi.configuration.production_key)
end