amplitude-api 0.1.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b743d15865f804837f6f3abb9557fa35aa6a32ae360fae0edfeaab0e7905b81
4
- data.tar.gz: 8c58bd5c4a21a36394cca7ce58da56b1e4135fc4ac574001e31350bda5cf3d69
3
+ metadata.gz: e4372cbca5a551be9721be89fbbe3ee80dc9216d8fa44fba7b0031a5e62785cd
4
+ data.tar.gz: ee6056b7e64c2b51f9365a8e57c90a1b4b8fc5edc406b1f7cbabf4caf831b7ad
5
5
  SHA512:
6
- metadata.gz: 3bf4707b9fe9905e95fdeee4c66044dfce02a2f4bae7fe939cffc343957ff4b2eb3d0dcf41d9c9dc958048f14fc8039c5d4e5c375103b7aeec4260e5a5a5c2d5
7
- data.tar.gz: 6cb4d59c569e8ccb3d8fc1f52920baba4ae6fa1da605115e6ed393a05119d1b275e58d00d18349cb840dd84b11b58416f3639e31eb95e4fb6c88eac55a378084
6
+ metadata.gz: f55a3e558f985bac1d78ac842532dfd5dfc69290f7ece8f9c197c71f155ae802de8a00649c5be9bcdd4a67e995e59eaf9cbcc3586808ddfedbb00aba259cf39b
7
+ data.tar.gz: 3e6d679080a879ccf02ab29b3f13839b29c78bfb28cd48793275345ca41b77a61d09231e82d3cc4132319d14eef0ac807e5fa589330a1e0f84486fa534f875a4
data/.gitignore CHANGED
@@ -27,11 +27,12 @@ build/
27
27
 
28
28
  # for a library or gem, you might want to ignore these files since the code is
29
29
  # intended to run in multiple environments; otherwise, check them in:
30
- # Gemfile.lock
31
- # .ruby-version
32
- # .ruby-gemset
30
+ Gemfile.lock
31
+ .ruby-version
32
+ .ruby-gemset
33
33
 
34
34
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
35
  .rvmrc
36
36
 
37
- .idea
37
+ .idea
38
+ amplitude-api.iml
data/.rubocop.yml CHANGED
@@ -1,8 +1,26 @@
1
1
  require: rubocop-rspec
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.4
5
+
2
6
  Metrics/LineLength:
3
7
  Max: 120
4
8
 
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
11
+ SupportedStyles:
12
+ - single_quotes
13
+ - double_quotes
14
+
15
+ Style/BlockDelimiters:
16
+ Enabled: true
17
+ Exclude:
18
+ - spec/**/*
19
+
5
20
  # Disable some failing rspec cops that fail from upgrading gems until we can clean things up a bit.
21
+ Naming/FileName:
22
+ Exclude:
23
+ - lib/amplitude-api.rb
6
24
  RSpec/ExampleLength:
7
25
  Enabled: false
8
26
  Metrics/BlockLength:
@@ -14,4 +32,4 @@ RSpec/NestedGroups:
14
32
  RSpec/MessageSpies:
15
33
  Enabled: false
16
34
  RSpec/ContextWording:
17
- Enabled: false
35
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.3.1
5
- - 2.2.2
6
- - 2.1.6
4
+ - 2.6
5
+ - 2.4
data/Changelog.md CHANGED
@@ -3,6 +3,38 @@
3
3
  We would like to think our many [contributors](https://github.com/toothrot/amplitude-api/graphs/contributors) for
4
4
  suggestions, ideas and improvements to Amplitude API.
5
5
 
6
+ ## 0.3.3 (2021-02-24)
7
+ * Relaxes Faraday dependency
8
+
9
+ ## 0.3.2 (2021-02-23)
10
+ * Creates new properties on initialization
11
+
12
+ ## 0.3.1 (2021-02-23)
13
+ * Allows sending options to Amplitude
14
+ * Solves an error when accessing event properties not been created yet
15
+
16
+ ## 0.3.0 (2021-02-22)
17
+
18
+ * Changes Typhoeus to Faraday to launch requests (**breaking change**)
19
+ * Adds new API fields to Event
20
+ * Event can now include arbitrary properties, so it could be used if the API adds new ones.
21
+
22
+ ## 0.2.0 (2021-02-14)
23
+
24
+ * Updates gem to use HTTP API V2.
25
+
26
+ ## 0.1.1 (2019-01-01)
27
+
28
+ * Fix #41 - Delete API now correctly handles Arrays of IDs.
29
+
30
+ ## 0.1.0 (2019-01-01)
31
+
32
+ * Update Gem dependencies (thanks @kolorahl, @itamar, @krettan)
33
+ * Minimum ruby version is now 2.2
34
+ * Support Delete API (thanks @samjohn)
35
+ * Fix bundle Inline (thanks @jonduarte)
36
+ * Many fixes from @kolorahl
37
+
6
38
  ## 0.0.10 (2017-09-13)
7
39
 
8
40
  * Allow to use "Event Segmentation" via API ([#23](https://github.com/toothrot/amplitude-api/pull/23)).
data/Gemfile CHANGED
@@ -1,12 +1,3 @@
1
- # Generated from /Users/alex/development/amplitude-api/amplitude-api.gemspec
2
- source 'https://rubygems.org'
3
-
4
- gem 'typhoeus', '~> 1.1'
5
-
6
- group :development, :test do
7
- gem 'pry', '~> 0.12.2'
8
- gem 'rake', '>= 12.0'
9
- gem 'rspec', '>= 2.99.0'
10
- gem 'rubocop', '~> 0.66.0', require: false
11
- gem 'rubocop-rspec'
12
- end
1
+ # frozen_string_literal: true
2
+ source "https://rubygems.org"
3
+ gemspec
data/Rakefile CHANGED
@@ -1,14 +1,16 @@
1
- require 'bundler/gem_tasks'
2
- require 'rubocop/rake_task'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
3
5
 
4
6
  RuboCop::RakeTask.new
5
7
 
6
8
  begin
7
- require 'rspec/core/rake_task'
9
+ require "rspec/core/rake_task"
8
10
  RSpec::Core::RakeTask.new(:spec)
9
11
  rescue LoadError
10
- puts 'Unable to load rspec. Have you run `bundle install`?'
12
+ puts "Unable to load rspec. Have you run `bundle install`?"
11
13
  end
12
14
 
13
15
  task(:default).clear
14
- task default: ['rubocop:auto_correct', :spec]
16
+ task default: ["rubocop:auto_correct", :spec]
@@ -1,25 +1,27 @@
1
- lib = File.expand_path('lib', __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'amplitude_api/version'
5
+ require "amplitude_api/version"
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = 'amplitude-api'
8
+ spec.name = "amplitude-api"
7
9
  spec.version = AmplitudeAPI::VERSION
8
- spec.authors = ['Alex Rakoczy']
9
- spec.email = ['arakoczy@gmail.com']
10
- spec.summary = 'Send events to the Amplitude API'
11
- spec.description = 'Provides an integration for sending events to Amplitude'
12
- spec.homepage = 'https://github.com/toothrot/amplitude-api'
13
- spec.license = 'MIT'
10
+ spec.authors = ["Alex Rakoczy"]
11
+ spec.email = ["arakoczy@gmail.com"]
12
+ spec.summary = "Send events to the Amplitude API"
13
+ spec.description = "Provides an integration for sending events to Amplitude"
14
+ spec.homepage = "https://github.com/toothrot/amplitude-api"
15
+ spec.license = "MIT"
14
16
 
15
17
  spec.files = `git ls-files -z`.split("\x0")
16
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ['lib']
20
+ spec.require_paths = ["lib"]
19
21
 
20
- spec.add_development_dependency 'pry', '~> 0.12.2'
21
- spec.add_development_dependency 'rake', '~> 12.0', '>= 12.0'
22
- spec.add_development_dependency 'rspec', '~> 2.99', '>= 2.99.0'
23
- spec.add_dependency 'typhoeus', '~> 1.0'
24
- spec.required_ruby_version = '~> 2.2'
22
+ spec.add_development_dependency "pry", "~> 0.12.2"
23
+ spec.add_development_dependency "rake", "~> 12.0", ">= 12.0"
24
+ spec.add_development_dependency "rspec", "~> 2.99", ">= 2.99.0"
25
+ spec.add_dependency "faraday", "~> 1.0"
26
+ spec.required_ruby_version = ">= 2.4"
25
27
  end
data/lib/amplitude-api.rb CHANGED
@@ -1,4 +1,3 @@
1
- # rubocop:disable Style/FileName
2
- require_relative 'amplitude_api'
3
- # rubocop:enable Style/FileName
4
- # Whoops.
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "amplitude_api"
data/lib/amplitude_api.rb CHANGED
@@ -1,18 +1,20 @@
1
- require 'json'
2
- require 'typhoeus'
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "faraday"
3
5
 
4
6
  # AmplitudeAPI
5
7
  class AmplitudeAPI
6
- require_relative 'amplitude_api/config'
7
- require_relative 'amplitude_api/event'
8
- require_relative 'amplitude_api/identification'
8
+ require_relative "amplitude_api/config"
9
+ require_relative "amplitude_api/event"
10
+ require_relative "amplitude_api/identification"
9
11
 
10
- TRACK_URI_STRING = 'https://api.amplitude.com/httpapi'.freeze
11
- IDENTIFY_URI_STRING = 'https://api.amplitude.com/identify'.freeze
12
- SEGMENTATION_URI_STRING = 'https://amplitude.com/api/2/events/segmentation'.freeze
13
- DELETION_URI_STRING = 'https://amplitude.com/api/2/deletions/users'.freeze
12
+ TRACK_URI_STRING = "https://api.amplitude.com/2/httpapi"
13
+ IDENTIFY_URI_STRING = "https://api.amplitude.com/identify"
14
+ SEGMENTATION_URI_STRING = "https://amplitude.com/api/2/events/segmentation"
15
+ DELETION_URI_STRING = "https://amplitude.com/api/2/deletions/users"
14
16
 
15
- USER_WITH_NO_ACCOUNT = "user who doesn't have an account".freeze
17
+ USER_WITH_NO_ACCOUNT = "user who doesn't have an account"
16
18
 
17
19
  class << self
18
20
  def config
@@ -38,12 +40,12 @@ class AmplitudeAPI
38
40
  # @param [ String ] event_name a string that describes the event, e.g. "clicked on Home"
39
41
  # @param [ String ] user a string or integer that uniquely identifies a user.
40
42
  # @param [ String ] device a string that uniquely identifies the device.
41
- # @param [ Hash ] event_properties a hash that is serialized to JSON,
43
+ # @option options [ Hash ] event_properties a hash that is serialized to JSON,
42
44
  # and can contain any other property to be stored on the Event
43
- # @param [ Hash ] user_properties a hash that is serialized to JSON,
45
+ # @option options [ Hash ] user_properties a hash that is serialized to JSON,
44
46
  # and contains user properties to be associated with the user
45
47
  #
46
- # @return [ Typhoeus::Response ]
48
+ # @return [ Faraday::Response ]
47
49
  def send_event(event_name, user, device, options = {})
48
50
  event = AmplitudeAPI::Event.new(
49
51
  user_id: user,
@@ -68,10 +70,13 @@ class AmplitudeAPI
68
70
  def track_body(*events)
69
71
  event_body = events.flatten.map(&:to_hash)
70
72
 
71
- {
73
+ body = {
72
74
  api_key: api_key,
73
- event: JSON.generate(event_body)
75
+ events: event_body
74
76
  }
77
+ body[:options] = config.options if config.options
78
+
79
+ JSON.generate(body)
75
80
  end
76
81
 
77
82
  # @overload track(event)
@@ -80,11 +85,11 @@ class AmplitudeAPI
80
85
  # @overload track([events])
81
86
  # @param [ Array<AmplitudeAPI::Event> ] Send an array of events in a single request to Amplitude
82
87
  #
83
- # @return [ Typhoeus::Response ]
88
+ # @return [ Faraday::Response ]
84
89
  #
85
90
  # Send one or more Events to the Amplitude API
86
91
  def track(*events)
87
- Typhoeus.post(TRACK_URI_STRING, body: track_body(events))
92
+ Faraday.post(TRACK_URI_STRING, track_body(events), "Content-Type" => "application/json")
88
93
  end
89
94
 
90
95
  # ==== Identification related methods
@@ -123,40 +128,40 @@ class AmplitudeAPI
123
128
  # @overload identify([identifications])
124
129
  # @param [ Array<AmplitudeAPI::Identify> ] Send an array of identifications in a single request to Amplitude
125
130
  #
126
- # @return [ Typhoeus::Response ]
131
+ # @return [ Faraday::Response ]
127
132
  #
128
133
  # Send one or more Identifications to the Amplitude Identify API
129
134
  def identify(*identifications)
130
- Typhoeus.post(IDENTIFY_URI_STRING, body: identify_body(identifications))
135
+ Faraday.post(IDENTIFY_URI_STRING, identify_body(identifications))
131
136
  end
132
137
 
133
138
  # ==== Event Segmentation related methods
134
139
 
135
140
  # Get metrics for an event with segmentation.
136
141
  #
137
- # @param [ Hash ] e a hash that defines event.
142
+ # @param [ Hash ] event a hash that defines event.
138
143
  # @param [ Time ] start_time a start time.
139
144
  # @param [ Time ] end_time a end time.
140
- # @param [ String ] m a string that defines aggregate function.
145
+ # @option options [ String ] m a string that defines aggregate function.
141
146
  # For non-property metrics: "uniques", "totals", "pct_dau", or "average" (default: "uniques").
142
147
  # For property metrics: "histogram", "sums", or "value_avg"
143
148
  # (note: a valid "group_by" value is required in parameter e).
144
- # @param [ Integer ] i an integer that defines segmentation interval.
149
+ # @option options [ Integer ] i an integer that defines segmentation interval.
145
150
  # Set to -300000, -3600000, 1, 7, or 30 for realtime, hourly, daily, weekly,
146
151
  # and monthly counts, respectively (default: 1). Realtime segmentation is capped at 2 days,
147
152
  # hourly segmentation is capped at 7 days, and daily at 365 days.
148
- # @param [ Array ] s an array that defines segment definitions.
149
- # @param [ String ] g a string that defines property to group by.
150
- # @param [ Integer ] limit an integer that defines number of Group By values
153
+ # @option options [ Array ] s an array that defines segment definitions.
154
+ # @option options [ String ] g a string that defines property to group by.
155
+ # @option options [ Integer ] limit an integer that defines number of Group By values
151
156
  # returned (default: 100). The maximum limit is 1000.
152
157
  #
153
- # @return [ Typhoeus::Response ]
158
+ # @return [ Faraday::Response ]
154
159
  def segmentation(event, start_time, end_time, **options)
155
- Typhoeus.get SEGMENTATION_URI_STRING, userpwd: "#{api_key}:#{secret_key}", params: {
160
+ Faraday.get SEGMENTATION_URI_STRING, userpwd: "#{api_key}:#{secret_key}", params: {
156
161
  e: event.to_json,
157
162
  m: options[:m],
158
- start: start_time.strftime('%Y%m%d'),
159
- end: end_time.strftime('%Y%m%d'),
163
+ start: start_time.strftime("%Y%m%d"),
164
+ end: end_time.strftime("%Y%m%d"),
160
165
  i: options[:i],
161
166
  s: (options[:s] || []).map(&:to_json),
162
167
  g: options[:g],
@@ -164,27 +169,48 @@ class AmplitudeAPI
164
169
  }.delete_if { |_, value| value.nil? }
165
170
  end
166
171
 
167
- # ==== GDPR compliance methods
168
-
169
- # Delete a user from amplitude when they request it to comply with GDPR
172
+ # Delete a user from amplitude
173
+ #
170
174
  # You must pass in either an array of user_ids or an array of amplitude_ids
171
175
  #
172
- # @param [ user_ids ] (optional) the user_ids to delete
176
+ # @param [ Array<String> ] (optional) the user_ids to delete
173
177
  # based on your database
174
- # @param [ amplitude_ids ] (optional) the amplitude_ids to delete
178
+ # @param [ Array<Integer> ] (optional) the amplitude_ids to delete
175
179
  # based on the amplitude database
176
- # @param [ requester ] the email address of the person who
180
+ # @param [ String ] requester the email address of the person who
177
181
  # is requesting the deletion, optional but useful for reporting
178
- #
179
- # @return [ Typhoeus::Response ]
180
- def delete(user_ids: nil, amplitude_ids: nil, requester: nil)
181
- Typhoeus.post DELETION_URI_STRING,
182
- userpwd: "#{api_key}:#{config.secret_key}",
183
- body: {
184
- amplitude_ids: amplitude_ids,
185
- user_ids: user_ids,
186
- requester: requester
187
- }.delete_if { |_, value| value.nil? }
182
+ # @param [ Boolean ] (optional) ignore any invalid user IDs(users that do no
183
+ # exist in the project) that were passed in
184
+ # @param [ Boolean ] (optional) delete from the entire org rather than just
185
+ # this project.
186
+ # @return [ Faraday::Response ]
187
+ def delete(user_ids: nil, amplitude_ids: nil, requester: nil, ignore_invalid_id: nil, delete_from_org: nil)
188
+ user_ids = Array(user_ids)
189
+ amplitude_ids = Array(amplitude_ids)
190
+
191
+ faraday = Faraday.new do |conn|
192
+ conn.basic_auth config.api_key, config.secret_key
193
+ end
194
+
195
+ faraday.post(
196
+ DELETION_URI_STRING,
197
+ delete_body(user_ids, amplitude_ids, requester, ignore_invalid_id, delete_from_org),
198
+ "Content-Type" => "application/json"
199
+ )
200
+ end
201
+
202
+ private
203
+
204
+ def delete_body(user_ids, amplitude_ids, requester, ignore_invalid_id, delete_from_org)
205
+ body = {
206
+ amplitude_ids: amplitude_ids,
207
+ user_ids: user_ids,
208
+ requester: requester
209
+ }.delete_if { |_, value| value.nil? || value.empty? }
210
+
211
+ body[:ignore_invalid_id] = ignore_invalid_id.to_s if ignore_invalid_id
212
+ body[:delete_from_org] = delete_from_org.to_s if delete_from_org
213
+ JSON.generate(body)
188
214
  end
189
215
  end
190
216
  end
@@ -1,4 +1,6 @@
1
- require 'singleton'
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
2
4
 
3
5
  class AmplitudeAPI
4
6
  # AmplitudeAPI::Config
@@ -6,20 +8,40 @@ class AmplitudeAPI
6
8
  include Singleton
7
9
 
8
10
  attr_accessor :api_key, :secret_key, :whitelist, :time_formatter,
9
- :event_properties_formatter, :user_properties_formatter
11
+ :event_properties_formatter, :user_properties_formatter,
12
+ :options
10
13
 
11
14
  def initialize
12
15
  self.class.defaults.each { |k, v| send("#{k}=", v) }
13
16
  end
14
17
 
15
18
  class << self
19
+ def base_properties
20
+ %i[event_type event_properties user_properties user_id device_id]
21
+ end
22
+
23
+ def revenue_properties
24
+ %i[revenue_type product_id revenue price quantity]
25
+ end
26
+
27
+ def optional_properties
28
+ %i[
29
+ time
30
+ ip platform country insert_id
31
+ groups app_version os_name os_version
32
+ device_brand device_manufacturer device_model
33
+ carrier region city dma language
34
+ location_lat location_lng
35
+ idfa idfv adid android_id
36
+ event_id session_id
37
+ ]
38
+ end
39
+
16
40
  def defaults
17
41
  {
18
42
  api_key: nil,
19
43
  secret_key: nil,
20
- whitelist: %i[user_id device_id event_type time
21
- event_properties user_properties time ip platform country insert_id
22
- revenue_type price quantity product_id],
44
+ whitelist: base_properties + revenue_properties + optional_properties,
23
45
  time_formatter: ->(time) { time ? time.to_i * 1_000 : nil },
24
46
  event_properties_formatter: ->(props) { props || {} },
25
47
  user_properties_formatter: ->(props) { props || {} }