klaviyo 0.9.3 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 438fe72ddfdd5e636f8026c8e0b02daf22586e58c4a2628065db088b633bb1be
4
+ data.tar.gz: c586d57114a208aa6843fa6dd218d2e2ceae454282c8b4b297a7ab122cd89dd3
5
+ SHA512:
6
+ metadata.gz: bce5653e39bc762647ee52f29a3c0b2d8ea672b782a5192e9ca3d3da11a41e388f67a5c11f7eb28ce7f274f691a445677ee345eb3855ba2fa422ed30407a282f
7
+ data.tar.gz: 5f831ad7a264a16b697435e1cafe6c942f7c58572bdf67041d74b3f65f398fd4ba948e0c70edbccb6d5839d16f0831553ce2868fe43b6b6fe796d9dfef2e2103
@@ -1,18 +1,18 @@
1
- files = ['klaviyo.gemspec', '{lib}/**/*'].map {|f| Dir[f]}.flatten
1
+ files = ['klaviyo.gemspec', '{lib}/**/**/*'].map {|f| Dir[f]}.flatten
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'klaviyo'
5
- s.version = '0.9.3'
6
- s.date = '2012-09-03'
5
+ s.version = '2.0.3'
6
+ s.date = '2021-01-11'
7
7
  s.summary = 'You heard us, a Ruby wrapper for the Klaviyo API'
8
8
  s.description = 'Ruby wrapper for the Klaviyo API'
9
- s.authors = ['Andrew Bialecki']
10
- s.email = 'andrew@klaviyo.com'
9
+ s.authors = ['Klaviyo Team']
10
+ s.email = 'libraries@klaviyo.com'
11
11
  s.files = files
12
- s.homepage = 'http://www.klaviyo.com/'
12
+ s.homepage = 'https://www.klaviyo.com/'
13
13
  s.require_path = 'lib'
14
- s.has_rdoc = false
15
14
  s.add_dependency 'json'
16
15
  s.add_dependency 'rack'
17
16
  s.add_dependency 'escape'
18
- end
17
+ s.add_dependency 'faraday'
18
+ end
@@ -1 +1 @@
1
- require 'klaviyo/client'
1
+ require 'klaviyo/klaviyo_module'
@@ -0,0 +1,41 @@
1
+ module Klaviyo
2
+ class Campaigns < Client
3
+ CANCEL = 'cancel'
4
+ CAMPAIGN = 'campaign'
5
+ CAMPAIGNS = 'campaigns'
6
+ SEND = 'send'
7
+
8
+ # Retrieves all the campaigns from Klaviyo account
9
+ # @return [List] of JSON formatted campaing objects
10
+ def self.get_campaigns()
11
+ v1_request(HTTP_GET, CAMPAIGNS)
12
+ end
13
+
14
+ # Retrieves the details of the list
15
+ # @param campaign_id the if of campaign
16
+ # @return [JSON] a JSON object containing information about the campaign
17
+ def self.get_campaign_details(campaign_id)
18
+ path = "#{CAMPAIGN}/#{campaign_id}"
19
+
20
+ v1_request(HTTP_GET, path)
21
+ end
22
+
23
+ # Sends the campaign immediately
24
+ # @param campaign_id [String] the id of campaign
25
+ # @return will return with HTTP ok in case of success
26
+ def self.send_campaign(campaign_id)
27
+ path = "#{CAMPAIGN}/#{campaign_id}/#{SEND}"
28
+
29
+ v1_request(HTTP_POST, path)
30
+ end
31
+
32
+ # Cancels the campaign with specified campaign_id
33
+ # @param campaign_id [String] the id of campaign
34
+ # @return [JSON] a JSON object containing the campaign details
35
+ def self.cancel_campaign(campaign_id)
36
+ path = "#{CAMPAIGN}/#{campaign_id}/#{CANCEL}"
37
+
38
+ v1_request(HTTP_POST, path)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,166 @@
1
+ module Klaviyo
2
+ class Lists < Client
3
+ EXCLUSIONS = 'exclusions'
4
+ GROUP = 'group'
5
+ LIST = 'list'
6
+ LISTS = 'lists'
7
+ MEMBERS = 'members'
8
+ SUBSCRIBE = 'subscribe'
9
+
10
+ # Creates a new list
11
+ # @param list_name [String] the list name
12
+ # @return will return with HTTP OK on success
13
+ def self.create_list(list_name)
14
+ body = {
15
+ :list_name => list_name
16
+ }
17
+ v2_request(HTTP_POST, LISTS, body)
18
+ end
19
+
20
+ # Retrieves all the lists in the Klaviyo account
21
+ # @return [List] a list of JSON objects of the name and id for each list
22
+ def self.get_lists()
23
+ v2_request(HTTP_GET, LISTS)
24
+ end
25
+
26
+ # Retrieves the details of the list
27
+ # @param list_id [String] the id of the list
28
+ # @return [JSON] a JSON object containing information about the list
29
+ def self.get_list_details(list_id)
30
+ path = "#{LIST}/#{list_id}"
31
+ v2_request(HTTP_GET, path)
32
+ end
33
+
34
+ # Updates the properties of a list
35
+ # @param list_id [String] the id of the list
36
+ # @param list_name [String] the new name of the list
37
+ # @return will return with HTTP OK on success
38
+ def self.update_list_details(list_id, list_name)
39
+ path = "#{LIST}/#{list_id}"
40
+ body = {
41
+ :list_name => list_name
42
+ }
43
+ v2_request(HTTP_PUT, path, body)
44
+ end
45
+
46
+ # Deletes a list
47
+ # @param list_id [String] the id of the list
48
+ # @return will return with HTTP OK on success
49
+ def self.delete_list(list_id)
50
+ path = "#{LIST}/#{list_id}"
51
+ v2_request(HTTP_DELETE, path)
52
+ end
53
+
54
+ # Check if profiles are in a list and not supressed
55
+ # @param list_id [String] the id of the list
56
+ # @param :emails [List] the emails of the profiles to check
57
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
58
+ # @param :push_tokens [List] push tokens of the profiles to check
59
+ # @return A list of JSON objects of the profiles. Profiles that are
60
+ # supressed or not found are not included.
61
+ def self.check_list_subscriptions(list_id, emails: [], phone_numbers: [], push_tokens: [])
62
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
63
+ params = {
64
+ :emails => emails,
65
+ :phone_numbers => phone_numbers,
66
+ :push_tokens => push_tokens
67
+ }
68
+ v2_request(HTTP_GET, path, params)
69
+ end
70
+
71
+ # Subscribe profiles to a list.
72
+ # @param list_id [String] the id of the list
73
+ # @param profiles [List] a list of JSON objects. Each object requires either
74
+ # an email or phone number key.
75
+ # @return will retun HTTP OK on success. If the list is single opt-in then a
76
+ # list of records containing the email address, phone number, push token,
77
+ # and the corresponding profile ID will also be included.
78
+ def self.add_subscribers_to_list(list_id, profiles: [])
79
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
80
+ params = {
81
+ :profiles => profiles
82
+ }
83
+ v2_request(HTTP_POST, path, params)
84
+ end
85
+
86
+ # Unsubscribe and remove profiles from a list
87
+ # @param list_id [String] the id of the list
88
+ # @param :emails [List] the emails of the profiles to check
89
+ # @return will return with HTTP OK on success
90
+ def self.unsubscribe_from_list(list_id, emails: [])
91
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
92
+ params = {
93
+ :emails => emails
94
+ }
95
+ v2_request(HTTP_DELETE, path, params)
96
+ end
97
+
98
+ # Add profiles to a list
99
+ # @param list_id [String] the id of the list
100
+ # @param :profiles [List] A list of JSON objects. Each object is a profile
101
+ # that will be added to the list
102
+ # @return will return with HTTP OK on success and a list of records of the
103
+ # corresponding profile id
104
+ def self.add_to_list(list_id, profiles: [])
105
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
106
+ params = {
107
+ :profiles => profiles
108
+ }
109
+ v2_request(HTTP_POST, path, params)
110
+ end
111
+
112
+ # Check if profiles are on a list
113
+ # @param list_id [String] the id of the list
114
+ # @param :emails [List] the emails of the profiles to check
115
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
116
+ # @param :push_tokens [List] push tokens of the profiles to check
117
+ # @return A list of JSON objects of the profiles. Profiles that are
118
+ # supressed or not found are not included.
119
+ def self.check_list_memberships(list_id, emails: [], phone_numbers: [], push_tokens: [])
120
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
121
+ params = {
122
+ :emails => emails,
123
+ :phone_numbers => phone_numbers,
124
+ :push_tokens => push_tokens
125
+ }
126
+ v2_request(HTTP_GET, path, params)
127
+ end
128
+
129
+ # Remove profiles from a list
130
+ # @param list_id [String] the id of the list
131
+ # @param :emails [List] the emails of the profiles to check
132
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
133
+ # @param :push_tokens [List] push tokens of the profiles to check
134
+ # @return will return with HTTP OK on success
135
+ def self.remove_from_list(list_id, emails: [], phone_numbers: [], push_tokens: [])
136
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
137
+ params = {
138
+ :emails => emails,
139
+ :phone_numbers => phone_numbers,
140
+ :push_tokens => push_tokens
141
+ }
142
+ v2_request(HTTP_DELETE, path, params)
143
+ end
144
+
145
+ # Get all emails, phone numbers, along with reasons for list exclusion
146
+ # @param list_id [String] the id of the list
147
+ # @param marker [Integer] a marker from a previous call to get the next batch
148
+ # @return [List] A list of JSON object for each profile with the reason for exclusion
149
+ def self.get_list_exclusions(list_id, marker: nil)
150
+ path = "#{LIST}/#{list_id}/#{EXCLUSIONS}/#{ALL}"
151
+ params = {
152
+ :marker => marker
153
+ }
154
+ v2_request(HTTP_GET, path, params)
155
+ end
156
+
157
+ # Get all of the emails, phone numbers, and push tokens for profiles in a given list or segment
158
+ # @param list_id [String] the id of the list
159
+ # @param marker [Integer] a marker from a previous call to get the next batch
160
+ # @return [List] A list of JSON objects for each profile with the id, email, phone number, and push token
161
+ def self.get_group_members(list_id)
162
+ path = "#{GROUP}/#{list_id}/#{MEMBERS}/#{ALL}"
163
+ v2_request(HTTP_GET, path)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,82 @@
1
+ module Klaviyo
2
+ class Metrics < Client
3
+ EXPORT = 'export'
4
+ METRIC = 'metric'
5
+ METRICS = 'metrics'
6
+
7
+ # Returns a list of all metrics in Klaviyo
8
+ # @param page [Integer] which page to return, default 0
9
+ # @param count [Integer] number of results to return, default 100
10
+ # @return a dictionary with a data property that contains an array of all the metrics
11
+ def self.get_metrics(page: DEFAULT_PAGE, count: DEFAULT_COUNT)
12
+ params = {
13
+ :page => page,
14
+ :count => count
15
+ }
16
+ v1_request(HTTP_GET, METRICS, params)
17
+ end
18
+
19
+ # Returns a batched timeline of all events in your Klaviyo account.
20
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
21
+ # @param count [Integer] number of results to return, default 100
22
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
23
+ # @return a dictionary with a data property that contains an array of the metrics
24
+ def self.get_metrics_timeline(since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
25
+ path = "#{METRICS}/#{TIMELINE}"
26
+ params = {
27
+ :since => since,
28
+ :count => count,
29
+ :sort => sort
30
+ }
31
+ v1_request(HTTP_GET, path, params)
32
+ end
33
+
34
+ # Returns a batched timeline for one specific type of metric.
35
+ # @param metric_id [String] the id of the metric
36
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
37
+ # @param count [Integer] number of results to return, default 100
38
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
39
+ # @return a dictionary with a data property that contains information about what metric the event tracks
40
+ def self.get_metric_timeline(metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
41
+ path = "#{METRIC}/#{metric_id}/#{TIMELINE}"
42
+ params = {
43
+ :since => since,
44
+ :count => count,
45
+ :sort => sort
46
+ }
47
+ v1_request(HTTP_GET, path, params)
48
+ end
49
+
50
+ # Export event data, optionally filtering and segmented on available event properties
51
+ # @param metric_id [String] the id of the metric
52
+ # @param start_date [String] Beginning of the timeframe to pull event data for. Default is 1 month ago
53
+ # @param end_date [String] End of the timeframe to pull event data for. Default is the current day
54
+ # @param unit [String] Granularity to bucket data points into - one of ‘day’, ‘week’, or ‘month’. Defaults to ‘day’.
55
+ # @param measurement [String or JSON-encoded list] Type of metric to fetch
56
+ # @param where [JSON-encoded list] Conditions to use to filter the set of events. A max of 1 condition can be given.
57
+ # @param by [String] The name of a property to segment the event data on. Where and by parameters cannot be specified at the same time.
58
+ # @param count [Integer] Maximum number of segments to return. The default value is 25.
59
+ # @return A dictionary relecting the input request parameters as well as a results property
60
+ def self.get_metric_export(metric_id,
61
+ start_date: nil,
62
+ end_date: nil,
63
+ unit: nil,
64
+ measurement: nil,
65
+ where: nil,
66
+ by: nil,
67
+ count: nil
68
+ )
69
+ path = "#{METRIC}/#{metric_id}/#{EXPORT}"
70
+ params = {
71
+ :start_date => start_date,
72
+ :end_date => end_date,
73
+ :unit => unit,
74
+ :measurement => measurement,
75
+ :where => where,
76
+ :by => by,
77
+ :count => count
78
+ }
79
+ v1_request(HTTP_GET, path, params)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,55 @@
1
+ module Klaviyo
2
+ class Profiles < Client
3
+ PERSON = 'person'
4
+
5
+ # Retrieve all the data attributes for a Klaviyo Person ID.
6
+ # @param person_id [String] the id of the profile
7
+ # @return returns a person object
8
+ def self.get_person_attributes(person_id)
9
+ path = "#{PERSON}/#{person_id}"
10
+ v1_request(HTTP_GET, path)
11
+ end
12
+
13
+ # Add or update one more more attributes for a Person
14
+ # @param person_id [String] the id of the profile
15
+ # @param kwargs [Key/value pairs] attributes to add/update in the profile
16
+ # @return returns the updated person object
17
+ def self.update_person_attributes(person_id, kwargs = {})
18
+ path = "#{PERSON}/#{person_id}"
19
+ v1_request(HTTP_PUT, path, kwargs)
20
+ end
21
+
22
+ # Listing a person's event timeline
23
+ # @param person_id [String] the id of the profile
24
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
25
+ # @param count [Integer] number of results to return, default 100
26
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
27
+ # @return returns a dictionary containing a list of metric event objects
28
+ def self.get_person_metrics_timeline(person_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
29
+ path = "#{PERSON}/#{person_id}/#{METRICS}/#{TIMELINE}"
30
+ params = {
31
+ :since => since,
32
+ :count => count,
33
+ :sort => sort
34
+ }
35
+ v1_request(HTTP_GET, path, params)
36
+ end
37
+
38
+ # Listing a person's event timeline for a particular metric
39
+ # @param person_id [String] the id of the profile
40
+ # @param metric_id [String] the id of the metric
41
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
42
+ # @param count [Integer] number of results to return, default 100
43
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
44
+ # @return returns a dictionary containing a list of metric event objects
45
+ def self.get_person_metric_timeline(person_id, metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
46
+ path = "#{PERSON}/#{person_id}/#{METRIC}/#{metric_id}/#{TIMELINE}"
47
+ params = {
48
+ :since => since,
49
+ :count => count,
50
+ :sort => sort
51
+ }
52
+ v1_request(HTTP_GET, path, params)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,79 @@
1
+ module Klaviyo
2
+ class Public < Client
3
+ # Used for identifying customers and managing profile properties
4
+ #
5
+ # @kwarg :id [String] the customer or profile id
6
+ # @kwarg :email [String] the customer or profile email
7
+ # @kwarg :properties [Hash] properties of the profile to add or update
8
+ def self.identify(kwargs = {})
9
+ defaults = {:id => nil,
10
+ :email => nil,
11
+ :phone_number => nil,
12
+ :properties => {}
13
+ }
14
+ kwargs = defaults.merge(kwargs)
15
+
16
+ unless check_required_args(kwargs)
17
+ return
18
+ end
19
+
20
+ properties = kwargs[:properties]
21
+ properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
22
+ properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
23
+ properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
24
+
25
+ params = {
26
+ :token => Klaviyo.public_api_key,
27
+ :properties => properties
28
+ }
29
+
30
+ public_request(HTTP_GET, 'identify', params)
31
+ end
32
+
33
+ # Used for tracking events and customer behaviors
34
+ #
35
+ # @param event [String] the event to track
36
+ # @kwarg :id [String] the customer or profile id
37
+ # @kwarg :email [String] the customer or profile email
38
+ # @kwarg :phone_number [String] the customer or profile phone number
39
+ # @kwarg :properties [Hash] properties of the event
40
+ # @kwargs :customer_properties [Hash] properties of the customer or profile
41
+ # @kwargs :time [Integer] timestamp of the event
42
+ def self.track(event, kwargs = {})
43
+ defaults = {
44
+ :id => nil,
45
+ :email => nil,
46
+ :phone_number => nil,
47
+ :properties => {},
48
+ :customer_properties => {},
49
+ :time => nil
50
+ }
51
+
52
+ kwargs = defaults.merge(kwargs)
53
+
54
+ unless check_required_args(kwargs)
55
+ return
56
+ end
57
+
58
+ customer_properties = kwargs[:customer_properties]
59
+ customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
60
+ customer_properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
61
+ customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
62
+
63
+ params = {
64
+ :token => Klaviyo.public_api_key,
65
+ :event => event,
66
+ :properties => kwargs[:properties],
67
+ :customer_properties => customer_properties
68
+ }
69
+ params[:time] = kwargs[:time].to_time.to_i if kwargs[:time]
70
+
71
+ public_request(HTTP_GET, 'track', params)
72
+ end
73
+
74
+ def self.track_once(event, kwargs = {})
75
+ kwargs.update('__track_once__' => true)
76
+ track(event, kwargs)
77
+ end
78
+ end
79
+ end
@@ -1,73 +1,95 @@
1
- require 'open-uri'
2
- require 'base64'
3
- require 'json'
4
- require 'klaviyo/client/middleware'
5
-
6
1
  module Klaviyo
7
- class KlaviyoError < StandardError; end
8
-
9
2
  class Client
10
- def initialize(api_key, url = 'http://a.klaviyo.com/')
11
- @api_key = api_key
12
- @url = url
13
- end
14
-
15
- def track(event, kwargs = {})
16
- defaults = {:id => nil, :email => nil, :properties => {}, :customer_properties => {}, :time => nil}
17
- kwargs = defaults.merge(kwargs)
18
-
19
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
20
- raise KlaviyoError.new('You must identify a user by email or ID')
21
- end
22
-
23
- customer_properties = kwargs[:customer_properties]
24
- customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
25
- customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
26
-
27
- params = build_params({
28
- :token => @api_key,
29
- :event => event,
30
- :properties => kwargs[:properties],
31
- :customer_properties => customer_properties,
32
- :ip => ''
3
+ BASE_API_URL = 'https://a.klaviyo.com/api'
4
+ V1_API = 'v1'
5
+ V2_API = 'v2'
6
+
7
+ HTTP_DELETE = 'delete'
8
+ HTTP_GET = 'get'
9
+ HTTP_POST = 'post'
10
+ HTTP_PUT = 'put'
11
+
12
+ ALL = 'all'
13
+ TIMELINE = 'timeline'
14
+
15
+ DEFAULT_COUNT = 100
16
+ DEFAULT_PAGE = 0
17
+ DEFAULT_SORT_DESC = 'desc'
18
+
19
+ private
20
+
21
+ def self.request(method, path, kwargs = {})
22
+ check_private_api_key_exists()
23
+ url = "#{BASE_API_URL}/#{path}"
24
+ connection = Faraday.new(
25
+ url: url,
26
+ headers: {
27
+ 'Content-Type' => 'application/json'
33
28
  })
34
- params[:time] = kwargs[:time].to_time.to_i if kwargs[:time]
35
- request('crm/api/track', params)
29
+ response = connection.send(method) do |req|
30
+ req.body = kwargs[:body].to_json || nil
31
+ end
32
+ end
33
+
34
+ def self.public_request(method, path, kwargs = {})
35
+ check_public_api_key_exists()
36
+ params = build_params(kwargs)
37
+ url = "#{BASE_API_URL}/#{path}?#{params}"
38
+ res = Faraday.get(url).body
39
+ end
40
+
41
+ def self.v1_request(method, path, kwargs = {})
42
+ defaults = {:page => nil,
43
+ :count => nil,
44
+ :since => nil,
45
+ :sort => nil}
46
+ params = defaults.merge(kwargs)
47
+ query_params = encode_params(params)
48
+ full_url = "#{V1_API}/#{path}?api_key=#{Klaviyo.private_api_key}#{query_params}"
49
+ request(method, full_url)
50
+ end
51
+
52
+ def self.v2_request(method, path, kwargs = {})
53
+ path = "#{V2_API}/#{path}"
54
+ key = {
55
+ "api_key": "#{Klaviyo.private_api_key}"
56
+ }
57
+ data = {}
58
+ data[:body] = key.merge(kwargs)
59
+ request(method, path, data)
36
60
  end
37
-
38
- def track_once(event, customer_properties = {}, properties = {})
39
- properties.update('__track_once__' => true)
40
- track(event, email, id, properties, customer_properties)
61
+
62
+ def self.build_params(params)
63
+ "data=#{Base64.encode64(JSON.generate(params)).gsub(/\n/,'')}"
41
64
  end
42
-
43
- def identify(kwargs = {})
44
- defaults = {:id => nil, :email => nil, :properties => {}}
45
- kwargs = defaults.merge(kwargs)
46
-
47
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
48
- raise KlaviyoError.new('You must identify a user by email or ID')
65
+
66
+ def self.check_required_args(kwargs)
67
+ if kwargs[:email].to_s.empty? and kwargs[:phone_number].to_s.empty? and kwargs[:id].to_s.empty?
68
+ raise Klaviyo::KlaviyoError.new(REQUIRED_ARG_ERROR)
69
+ else
70
+ return true
49
71
  end
50
-
51
- properties = kwargs[:properties]
52
- properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
53
- properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
72
+ end
54
73
 
55
- params = build_params({
56
- :token => @api_key,
57
- :properties => properties
58
- })
59
- request('crm/api/identify', params)
74
+ def self.check_private_api_key_exists()
75
+ if !Klaviyo.private_api_key
76
+ raise KlaviyoError.new(NO_PRIVATE_API_KEY_ERROR)
77
+ end
60
78
  end
61
79
 
62
- private
63
-
64
- def build_params(params)
65
- 'data=' + Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
80
+ def self.check_public_api_key_exists()
81
+ if !Klaviyo.public_api_key
82
+ raise KlaviyoError.new(NO_PUBLIC_API_KEY_ERROR)
83
+ end
66
84
  end
67
-
68
- def request(path, params)
69
- url = @url + path + '?' + params
70
- open(url).read == '1' ? true : false
85
+
86
+ def self.encode_params(kwargs)
87
+ kwargs.select!{|k, v| v}
88
+ params = URI.encode_www_form(kwargs)
89
+
90
+ if !params.empty?
91
+ return "&#{params}"
92
+ end
71
93
  end
72
94
  end
73
95
  end
@@ -0,0 +1,24 @@
1
+ require 'open-uri'
2
+ require 'base64'
3
+ require 'json'
4
+ require 'faraday'
5
+
6
+ require_relative './client'
7
+ require_relative 'apis/public'
8
+ require_relative 'apis/lists'
9
+ require_relative 'apis/metrics'
10
+ require_relative 'apis/profiles'
11
+ require_relative 'apis/campaigns'
12
+
13
+ module Klaviyo
14
+ class << self
15
+ attr_accessor :public_api_key
16
+ attr_accessor :private_api_key
17
+ end
18
+
19
+ class KlaviyoError < StandardError; end
20
+
21
+ NO_PRIVATE_API_KEY_ERROR = 'Please provide your Private API key for this request'
22
+ NO_PUBLIC_API_KEY_ERROR = 'Please provide your Public API key for this request'
23
+ REQUIRED_ARG_ERROR = 'You must identify a user by email, ID or phone_number'
24
+ end
@@ -0,0 +1,68 @@
1
+ module Rack
2
+ class Klaviyo
3
+ def initialize(app, api_key, options={})
4
+ @app = app
5
+ @api_key = api_key
6
+ @options = {
7
+ :insert_js_last => true
8
+ }.merge(options)
9
+ end
10
+
11
+ def call(env)
12
+ @env = env
13
+
14
+ @status, @headers, @response = @app.call(env)
15
+
16
+ if is_trackable_response?
17
+ update_response!
18
+ update_content_length!
19
+ end
20
+
21
+ [@status, @headers, @response]
22
+ end
23
+
24
+ private
25
+
26
+ def update_response!
27
+ @response.each do |part|
28
+ insert_at = part.index(@options[:insert_js_last] ? '</body' : '</head')
29
+ unless insert_at.nil?
30
+ part.insert(insert_at, render_script)
31
+ end
32
+ end
33
+ end
34
+
35
+ def update_content_length!
36
+ new_size = 0
37
+ @response.each{|part| new_size += part.bytesize}
38
+ @headers.merge!('Content-Length' => new_size.to_s)
39
+ end
40
+
41
+ def is_ajax_request?
42
+ @env.has_key?('HTTP_X_REQUESTED_WITH') && @env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
43
+ end
44
+
45
+ def is_html_response?
46
+ @headers['Content-Type'].include?('text/html') if @headers.has_key?('Content-Type')
47
+ end
48
+
49
+ def is_trackable_response?
50
+ is_html_response? && !is_ajax_request?
51
+ end
52
+
53
+ def render_script
54
+ <<-EOT
55
+ <script text="text/javascript">
56
+ var _learnq = _learnq || [];
57
+ _learnq.push(['account', '#{@api_key}']);
58
+
59
+ (function () {
60
+ var b = document.createElement('script'); b.type = 'text/javascript'; b.async = true;
61
+ b.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'a.klaviyo.com/media/js/analytics/analytics.js';
62
+ var a = document.getElementsByTagName('script')[0]; a.parentNode.insertBefore(b, a);
63
+ })();
64
+ </script>
65
+ EOT
66
+ end
67
+ end
68
+ end
metadata CHANGED
@@ -1,96 +1,107 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klaviyo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
5
- prerelease:
4
+ version: 2.0.3
6
5
  platform: ruby
7
6
  authors:
8
- - Andrew Bialecki
9
- autorequire:
7
+ - Klaviyo Team
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-09-03 00:00:00.000000000 Z
11
+ date: 2021-01-11 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: json
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rack
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: escape
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
62
69
  description: Ruby wrapper for the Klaviyo API
63
- email: andrew@klaviyo.com
70
+ email: libraries@klaviyo.com
64
71
  executables: []
65
72
  extensions: []
66
73
  extra_rdoc_files: []
67
74
  files:
68
75
  - klaviyo.gemspec
69
- - lib/klaviyo/client/middleware.rb
70
- - lib/klaviyo/client.rb
71
76
  - lib/klaviyo.rb
72
- homepage: http://www.klaviyo.com/
77
+ - lib/klaviyo/apis/campaigns.rb
78
+ - lib/klaviyo/apis/lists.rb
79
+ - lib/klaviyo/apis/metrics.rb
80
+ - lib/klaviyo/apis/profiles.rb
81
+ - lib/klaviyo/apis/public.rb
82
+ - lib/klaviyo/client.rb
83
+ - lib/klaviyo/klaviyo_module.rb
84
+ - lib/rack/klaviyo.rb
85
+ homepage: https://www.klaviyo.com/
73
86
  licenses: []
74
- post_install_message:
87
+ metadata: {}
88
+ post_install_message:
75
89
  rdoc_options: []
76
90
  require_paths:
77
91
  - lib
78
92
  required_ruby_version: !ruby/object:Gem::Requirement
79
- none: false
80
93
  requirements:
81
- - - ! '>='
94
+ - - ">="
82
95
  - !ruby/object:Gem::Version
83
96
  version: '0'
84
97
  required_rubygems_version: !ruby/object:Gem::Requirement
85
- none: false
86
98
  requirements:
87
- - - ! '>='
99
+ - - ">="
88
100
  - !ruby/object:Gem::Version
89
101
  version: '0'
90
102
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 1.8.24
93
- signing_key:
94
- specification_version: 3
103
+ rubygems_version: 3.0.8
104
+ signing_key:
105
+ specification_version: 4
95
106
  summary: You heard us, a Ruby wrapper for the Klaviyo API
96
107
  test_files: []
@@ -1,72 +0,0 @@
1
- require 'rack'
2
-
3
- module Klaviyo
4
- class Client
5
- class Middleware
6
- def initialize(app, api_key, options={})
7
- @app = app
8
- @api_key = api_key
9
- @options = {
10
- :insert_js_last => true
11
- }.merge(options)
12
- end
13
-
14
- def call(env)
15
- @env = env
16
-
17
- @status, @headers, @response = @app.call(env)
18
-
19
- if is_trackable_response?
20
- update_response!
21
- update_content_length!
22
- end
23
-
24
- [@status, @headers, @response]
25
- end
26
-
27
- private
28
-
29
- def update_response!
30
- @response.each do |part|
31
- insert_at = part.index(@options[:insert_js_last] ? '</body' : '</head')
32
- unless insert_at.nil?
33
- part.insert(insert_at, render_script)
34
- end
35
- end
36
- end
37
-
38
- def update_content_length!
39
- new_size = 0
40
- @response.each{|part| new_size += part.bytesize}
41
- @headers.merge!('Content-Length' => new_size.to_s)
42
- end
43
-
44
- def is_ajax_request?
45
- @env.has_key?('HTTP_X_REQUESTED_WITH') && @env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
46
- end
47
-
48
- def is_html_response?
49
- @headers['Content-Type'].include?('text/html') if @headers.has_key?('Content-Type')
50
- end
51
-
52
- def is_trackable_response?
53
- is_html_response? && !is_ajax_request?
54
- end
55
-
56
- def render_script
57
- <<-EOT
58
- <script text="text/javascript">
59
- var _learnq = _learnq || [];
60
- _learnq.push(['account', '#{@api_key}']);
61
-
62
- (function () {
63
- var b = document.createElement('script'); b.type = 'text/javascript'; b.async = true;
64
- b.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'a.klaviyo.com/media/js/learnmarklet.js';
65
- var a = document.getElementsByTagName('script')[0]; a.parentNode.insertBefore(b, a);
66
- })();
67
- </script>
68
- EOT
69
- end
70
- end
71
- end
72
- end