ahoy_matey 1.5.5 → 4.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +184 -34
- data/CONTRIBUTING.md +42 -0
- data/LICENSE.txt +1 -1
- data/README.md +464 -407
- data/app/controllers/ahoy/base_controller.rb +23 -15
- data/app/controllers/ahoy/events_controller.rb +8 -2
- data/app/controllers/ahoy/visits_controller.rb +8 -1
- data/app/jobs/ahoy/geocode_job.rb +11 -0
- data/app/jobs/ahoy/geocode_v2_job.rb +31 -0
- data/config/routes.rb +1 -1
- data/lib/ahoy/base_store.rb +101 -0
- data/lib/ahoy/controller.rb +23 -16
- data/lib/ahoy/database_store.rb +94 -0
- data/lib/ahoy/engine.rb +14 -7
- data/lib/ahoy/helper.rb +40 -0
- data/lib/ahoy/model.rb +5 -27
- data/lib/ahoy/query_methods.rb +88 -0
- data/lib/ahoy/tracker.rb +105 -51
- data/lib/ahoy/utils.rb +7 -0
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy/visit_properties.rb +99 -37
- data/lib/ahoy.rb +83 -93
- data/lib/ahoy_matey.rb +1 -1
- data/lib/generators/ahoy/activerecord_generator.rb +67 -0
- data/lib/generators/ahoy/base_generator.rb +13 -0
- data/lib/generators/ahoy/install_generator.rb +44 -0
- data/lib/generators/ahoy/mongoid_generator.rb +16 -0
- data/lib/generators/ahoy/templates/active_record_event_model.rb.tt +10 -0
- data/lib/generators/ahoy/templates/active_record_migration.rb.tt +62 -0
- data/lib/generators/ahoy/templates/active_record_visit_model.rb.tt +6 -0
- data/lib/generators/ahoy/templates/base_store_initializer.rb.tt +25 -0
- data/lib/generators/ahoy/templates/database_store_initializer.rb.tt +10 -0
- data/lib/generators/ahoy/{stores/templates/mongoid_event_model.rb → templates/mongoid_event_model.rb.tt} +4 -2
- data/lib/generators/ahoy/{stores/templates/mongoid_visit_model.rb → templates/mongoid_visit_model.rb.tt} +15 -9
- data/vendor/assets/javascripts/ahoy.js +271 -133
- metadata +37 -273
- data/.gitignore +0 -17
- data/Gemfile +0 -6
- data/Rakefile +0 -8
- data/ahoy_matey.gemspec +0 -38
- data/lib/ahoy/deckhands/location_deckhand.rb +0 -49
- data/lib/ahoy/deckhands/request_deckhand.rb +0 -52
- data/lib/ahoy/deckhands/technology_deckhand.rb +0 -47
- data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -22
- data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +0 -23
- data/lib/ahoy/geocode_job.rb +0 -13
- data/lib/ahoy/logger_silencer.rb +0 -75
- data/lib/ahoy/properties.rb +0 -58
- data/lib/ahoy/stores/active_record_store.rb +0 -61
- data/lib/ahoy/stores/active_record_token_store.rb +0 -114
- data/lib/ahoy/stores/base_store.rb +0 -88
- data/lib/ahoy/stores/bunny_store.rb +0 -33
- data/lib/ahoy/stores/fluentd_store.rb +0 -17
- data/lib/ahoy/stores/kafka_store.rb +0 -40
- data/lib/ahoy/stores/kinesis_firehose_store.rb +0 -42
- data/lib/ahoy/stores/log_store.rb +0 -53
- data/lib/ahoy/stores/mongoid_store.rb +0 -63
- data/lib/ahoy/stores/nats_store.rb +0 -34
- data/lib/ahoy/stores/nsq_store.rb +0 -36
- data/lib/ahoy/subscribers/active_record.rb +0 -19
- data/lib/ahoy/throttle.rb +0 -17
- data/lib/generators/ahoy/stores/active_record_events_generator.rb +0 -53
- data/lib/generators/ahoy/stores/active_record_generator.rb +0 -16
- data/lib/generators/ahoy/stores/active_record_visits_generator.rb +0 -43
- data/lib/generators/ahoy/stores/bunny_generator.rb +0 -15
- data/lib/generators/ahoy/stores/custom_generator.rb +0 -15
- data/lib/generators/ahoy/stores/fluentd_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kafka_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kinesis_firehose_generator.rb +0 -15
- data/lib/generators/ahoy/stores/log_generator.rb +0 -15
- data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -19
- data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -14
- data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -27
- data/lib/generators/ahoy/stores/nats_generator.rb +0 -15
- data/lib/generators/ahoy/stores/nsq_generator.rb +0 -15
- data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +0 -12
- data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +0 -19
- data/lib/generators/ahoy/stores/templates/active_record_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/active_record_visit_model.rb +0 -4
- data/lib/generators/ahoy/stores/templates/active_record_visits_migration.rb +0 -57
- data/lib/generators/ahoy/stores/templates/bunny_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -10
- data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/kafka_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/kinesis_firehose_initializer.rb +0 -17
- data/lib/generators/ahoy/stores/templates/log_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/mongoid_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/nats_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/nsq_initializer.rb +0 -9
- data/test/properties/mysql_json_test.rb +0 -18
- data/test/properties/mysql_text_test.rb +0 -19
- data/test/properties/postgresql_hstore_test.rb +0 -18
- data/test/properties/postgresql_json_test.rb +0 -18
- data/test/properties/postgresql_jsonb_test.rb +0 -18
- data/test/properties/postgresql_text_test.rb +0 -19
- data/test/test_helper.rb +0 -99
- data/test/visit_properties_test.rb +0 -44
data/lib/ahoy/tracker.rb
CHANGED
@@ -1,46 +1,60 @@
|
|
1
|
+
require "active_support/core_ext/digest/uuid"
|
2
|
+
|
1
3
|
module Ahoy
|
2
4
|
class Tracker
|
5
|
+
UUID_NAMESPACE = "a82ae811-5011-45ab-a728-569df7499c5f"
|
6
|
+
|
3
7
|
attr_reader :request, :controller
|
4
8
|
|
5
|
-
def initialize(options
|
9
|
+
def initialize(**options)
|
6
10
|
@store = Ahoy::Store.new(options.merge(ahoy: self))
|
7
11
|
@controller = options[:controller]
|
8
12
|
@request = options[:request] || @controller.try(:request)
|
13
|
+
@visit_token = options[:visit_token]
|
14
|
+
@user = options[:user]
|
9
15
|
@options = options
|
10
16
|
end
|
11
17
|
|
18
|
+
# can't use keyword arguments here
|
12
19
|
def track(name, properties = {}, options = {})
|
13
20
|
if exclude?
|
14
21
|
debug "Event excluded"
|
15
|
-
elsif missing_params?
|
16
|
-
debug "Missing required parameters"
|
17
22
|
else
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
data = {
|
24
|
+
visit_token: visit_token,
|
25
|
+
user_id: user.try(:id),
|
26
|
+
name: name.to_s,
|
27
|
+
properties: properties,
|
28
|
+
time: trusted_time(options[:time]),
|
29
|
+
event_id: options[:id] || generate_id
|
30
|
+
}.select { |_, v| v }
|
31
|
+
|
32
|
+
@store.track_event(data)
|
24
33
|
end
|
25
34
|
true
|
26
35
|
rescue => e
|
27
36
|
report_exception(e)
|
28
37
|
end
|
29
38
|
|
30
|
-
def track_visit(
|
39
|
+
def track_visit(defer: false, started_at: nil)
|
31
40
|
if exclude?
|
32
41
|
debug "Visit excluded"
|
33
|
-
elsif missing_params?
|
34
|
-
debug "Missing required parameters"
|
35
42
|
else
|
36
|
-
if
|
43
|
+
if defer
|
37
44
|
set_cookie("ahoy_track", true, nil, false)
|
38
45
|
else
|
39
|
-
|
46
|
+
delete_cookie("ahoy_track")
|
40
47
|
|
41
|
-
|
48
|
+
data = {
|
49
|
+
visit_token: visit_token,
|
50
|
+
visitor_token: visitor_token,
|
51
|
+
user_id: user.try(:id),
|
52
|
+
started_at: trusted_time(started_at),
|
53
|
+
}.merge(visit_properties).select { |_, v| v }
|
42
54
|
|
43
|
-
@store.track_visit(
|
55
|
+
@store.track_visit(data)
|
56
|
+
|
57
|
+
Ahoy::GeocodeV2Job.perform_later(visit_token, data[:ip]) if Ahoy.geocode && data[:ip]
|
44
58
|
end
|
45
59
|
end
|
46
60
|
true
|
@@ -48,11 +62,28 @@ module Ahoy
|
|
48
62
|
report_exception(e)
|
49
63
|
end
|
50
64
|
|
65
|
+
def geocode(data)
|
66
|
+
data = {
|
67
|
+
visit_token: visit_token
|
68
|
+
}.merge(data).select { |_, v| v }
|
69
|
+
|
70
|
+
@store.geocode(data)
|
71
|
+
true
|
72
|
+
rescue => e
|
73
|
+
report_exception(e)
|
74
|
+
end
|
75
|
+
|
51
76
|
def authenticate(user)
|
52
77
|
if exclude?
|
53
78
|
debug "Authentication excluded"
|
54
79
|
else
|
55
|
-
@store.
|
80
|
+
@store.user = user
|
81
|
+
|
82
|
+
data = {
|
83
|
+
visit_token: visit_token,
|
84
|
+
user_id: user.try(:id)
|
85
|
+
}
|
86
|
+
@store.authenticate(data)
|
56
87
|
end
|
57
88
|
true
|
58
89
|
rescue => e
|
@@ -63,16 +94,12 @@ module Ahoy
|
|
63
94
|
@visit ||= @store.visit
|
64
95
|
end
|
65
96
|
|
66
|
-
def
|
67
|
-
@
|
68
|
-
end
|
69
|
-
|
70
|
-
def visitor_id
|
71
|
-
@visitor_id ||= ensure_uuid(visitor_token_helper)
|
97
|
+
def visit_or_create
|
98
|
+
@visit ||= @store.visit_or_create
|
72
99
|
end
|
73
100
|
|
74
101
|
def new_visit?
|
75
|
-
!existing_visit_token
|
102
|
+
Ahoy.cookies ? !existing_visit_token : visit.nil?
|
76
103
|
end
|
77
104
|
|
78
105
|
def new_visitor?
|
@@ -80,12 +107,12 @@ module Ahoy
|
|
80
107
|
end
|
81
108
|
|
82
109
|
def set_visit_cookie
|
83
|
-
set_cookie("ahoy_visit",
|
110
|
+
set_cookie("ahoy_visit", visit_token, Ahoy.visit_duration)
|
84
111
|
end
|
85
112
|
|
86
113
|
def set_visitor_cookie
|
87
114
|
if new_visitor?
|
88
|
-
set_cookie("ahoy_visitor",
|
115
|
+
set_cookie("ahoy_visitor", visitor_token, Ahoy.visitor_duration)
|
89
116
|
end
|
90
117
|
end
|
91
118
|
|
@@ -93,18 +120,30 @@ module Ahoy
|
|
93
120
|
@user ||= @store.user
|
94
121
|
end
|
95
122
|
|
96
|
-
# TODO better name
|
97
123
|
def visit_properties
|
98
|
-
@visit_properties ||= Ahoy::VisitProperties.new(request, api: api?)
|
124
|
+
@visit_properties ||= request ? Ahoy::VisitProperties.new(request, api: api?).generate : {}
|
99
125
|
end
|
100
126
|
|
101
127
|
def visit_token
|
102
128
|
@visit_token ||= ensure_token(visit_token_helper)
|
103
129
|
end
|
130
|
+
alias_method :visit_id, :visit_token
|
104
131
|
|
105
132
|
def visitor_token
|
106
133
|
@visitor_token ||= ensure_token(visitor_token_helper)
|
107
134
|
end
|
135
|
+
alias_method :visitor_id, :visitor_token
|
136
|
+
|
137
|
+
def reset
|
138
|
+
reset_visit
|
139
|
+
delete_cookie("ahoy_visitor")
|
140
|
+
end
|
141
|
+
|
142
|
+
def reset_visit
|
143
|
+
delete_cookie("ahoy_visit")
|
144
|
+
delete_cookie("ahoy_events")
|
145
|
+
delete_cookie("ahoy_track")
|
146
|
+
end
|
108
147
|
|
109
148
|
protected
|
110
149
|
|
@@ -112,8 +151,9 @@ module Ahoy
|
|
112
151
|
@options[:api]
|
113
152
|
end
|
114
153
|
|
154
|
+
# private, but used by API
|
115
155
|
def missing_params?
|
116
|
-
if api? && Ahoy.protect_from_forgery
|
156
|
+
if Ahoy.cookies && api? && Ahoy.protect_from_forgery
|
117
157
|
!(existing_visit_token && existing_visitor_token)
|
118
158
|
else
|
119
159
|
false
|
@@ -121,35 +161,42 @@ module Ahoy
|
|
121
161
|
end
|
122
162
|
|
123
163
|
def set_cookie(name, value, duration = nil, use_domain = true)
|
124
|
-
|
125
|
-
|
126
|
-
|
164
|
+
# safety net
|
165
|
+
return unless Ahoy.cookies && request
|
166
|
+
|
167
|
+
cookie = Ahoy.cookie_options.merge(value: value)
|
127
168
|
cookie[:expires] = duration.from_now if duration
|
128
|
-
domain
|
129
|
-
cookie[:domain]
|
169
|
+
# prefer cookie_options[:domain] over cookie_domain
|
170
|
+
cookie[:domain] ||= Ahoy.cookie_domain if Ahoy.cookie_domain
|
171
|
+
cookie.delete(:domain) unless use_domain
|
130
172
|
request.cookie_jar[name] = cookie
|
131
173
|
end
|
132
174
|
|
133
|
-
def
|
175
|
+
def delete_cookie(name)
|
176
|
+
request.cookie_jar.delete(name) if request && request.cookie_jar[name]
|
177
|
+
end
|
178
|
+
|
179
|
+
def trusted_time(time = nil)
|
134
180
|
if !time || (api? && !(1.minute.ago..Time.now).cover?(time))
|
135
|
-
Time.
|
181
|
+
Time.current
|
136
182
|
else
|
137
183
|
time
|
138
184
|
end
|
139
185
|
end
|
140
186
|
|
141
187
|
def exclude?
|
142
|
-
@
|
188
|
+
unless defined?(@exclude)
|
189
|
+
@exclude = @store.exclude?
|
190
|
+
end
|
191
|
+
@exclude
|
143
192
|
end
|
144
193
|
|
145
|
-
# odd pattern for backwards compatibility
|
146
|
-
# TODO remove this method in next major release
|
147
194
|
def report_exception(e)
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
195
|
+
if defined?(ActionDispatch::RemoteIp::IpSpoofAttackError) && e.is_a?(ActionDispatch::RemoteIp::IpSpoofAttackError)
|
196
|
+
debug "Tracking excluded due to IP spoofing"
|
197
|
+
else
|
198
|
+
raise e if !defined?(Rails) || Rails.env.development? || Rails.env.test?
|
199
|
+
Safely.report_exception(e)
|
153
200
|
end
|
154
201
|
end
|
155
202
|
|
@@ -160,6 +207,7 @@ module Ahoy
|
|
160
207
|
def visit_token_helper
|
161
208
|
@visit_token_helper ||= begin
|
162
209
|
token = existing_visit_token
|
210
|
+
token ||= visit_anonymity_set unless Ahoy.cookies
|
163
211
|
token ||= generate_id unless Ahoy.api_only
|
164
212
|
token
|
165
213
|
end
|
@@ -168,6 +216,7 @@ module Ahoy
|
|
168
216
|
def visitor_token_helper
|
169
217
|
@visitor_token_helper ||= begin
|
170
218
|
token = existing_visitor_token
|
219
|
+
token ||= visitor_anonymity_set unless Ahoy.cookies
|
171
220
|
token ||= generate_id unless Ahoy.api_only
|
172
221
|
token
|
173
222
|
end
|
@@ -176,7 +225,7 @@ module Ahoy
|
|
176
225
|
def existing_visit_token
|
177
226
|
@existing_visit_token ||= begin
|
178
227
|
token = visit_header
|
179
|
-
token ||= visit_cookie
|
228
|
+
token ||= visit_cookie if Ahoy.cookies && !(api? && Ahoy.protect_from_forgery)
|
180
229
|
token ||= visit_param if api?
|
181
230
|
token
|
182
231
|
end
|
@@ -185,12 +234,20 @@ module Ahoy
|
|
185
234
|
def existing_visitor_token
|
186
235
|
@existing_visitor_token ||= begin
|
187
236
|
token = visitor_header
|
188
|
-
token ||= visitor_cookie
|
237
|
+
token ||= visitor_cookie if Ahoy.cookies && !(api? && Ahoy.protect_from_forgery)
|
189
238
|
token ||= visitor_param if api?
|
190
239
|
token
|
191
240
|
end
|
192
241
|
end
|
193
242
|
|
243
|
+
def visit_anonymity_set
|
244
|
+
@visit_anonymity_set ||= Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visit", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
|
245
|
+
end
|
246
|
+
|
247
|
+
def visitor_anonymity_set
|
248
|
+
@visitor_anonymity_set ||= Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visitor", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
|
249
|
+
end
|
250
|
+
|
194
251
|
def visit_cookie
|
195
252
|
@visit_cookie ||= request && request.cookies["ahoy_visit"]
|
196
253
|
end
|
@@ -215,16 +272,13 @@ module Ahoy
|
|
215
272
|
@visitor_param ||= request && request.params["visitor_token"]
|
216
273
|
end
|
217
274
|
|
218
|
-
def ensure_uuid(id)
|
219
|
-
Ahoy.ensure_uuid(id) if id
|
220
|
-
end
|
221
|
-
|
222
275
|
def ensure_token(token)
|
276
|
+
token = Ahoy::Utils.ensure_utf8(token)
|
223
277
|
token.to_s.gsub(/[^a-z0-9\-]/i, "").first(64) if token
|
224
278
|
end
|
225
279
|
|
226
280
|
def debug(message)
|
227
|
-
|
281
|
+
Ahoy.log message
|
228
282
|
end
|
229
283
|
end
|
230
284
|
end
|
data/lib/ahoy/utils.rb
ADDED
data/lib/ahoy/version.rb
CHANGED
@@ -1,60 +1,122 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "device_detector"
|
3
|
+
require "uri"
|
4
|
+
|
1
5
|
module Ahoy
|
2
6
|
class VisitProperties
|
3
|
-
|
4
|
-
TRAFFIC_SOURCE_KEYS = [:referring_domain, :search_keyword]
|
5
|
-
UTM_PARAMETER_KEYS = [:utm_source, :utm_medium, :utm_term, :utm_content, :utm_campaign]
|
6
|
-
TECHNOLOGY_KEYS = [:browser, :os, :device_type]
|
7
|
-
LOCATION_KEYS = [:country, :region, :city, :postal_code, :latitude, :longitude]
|
8
|
-
|
9
|
-
KEYS = REQUEST_KEYS + TRAFFIC_SOURCE_KEYS + UTM_PARAMETER_KEYS + TECHNOLOGY_KEYS + LOCATION_KEYS
|
7
|
+
attr_reader :request, :params, :referrer, :landing_page
|
10
8
|
|
11
|
-
|
12
|
-
delegate(*TRAFFIC_SOURCE_KEYS, to: :traffic_source_deckhand)
|
13
|
-
delegate(*(UTM_PARAMETER_KEYS + [:landing_params]), to: :utm_parameter_deckhand)
|
14
|
-
delegate(*TECHNOLOGY_KEYS, to: :technology_deckhand)
|
15
|
-
delegate(*LOCATION_KEYS, to: :location_deckhand)
|
16
|
-
|
17
|
-
def initialize(request, options = {})
|
9
|
+
def initialize(request, api:)
|
18
10
|
@request = request
|
19
|
-
@
|
11
|
+
@params = request.params
|
12
|
+
@referrer = api ? params["referrer"] : request.referer
|
13
|
+
@landing_page = api ? params["landing_page"] : request.original_url
|
20
14
|
end
|
21
15
|
|
22
|
-
def
|
23
|
-
|
16
|
+
def generate
|
17
|
+
@generate ||= request_properties.merge(tech_properties).merge(traffic_properties).merge(utm_properties)
|
24
18
|
end
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
private
|
21
|
+
|
22
|
+
def utm_properties
|
23
|
+
landing_params = {}
|
24
|
+
begin
|
25
|
+
landing_uri = URI.parse(landing_page)
|
26
|
+
# could also use Rack::Utils.parse_nested_query
|
27
|
+
landing_params = CGI.parse(landing_uri.query) if landing_uri
|
28
|
+
rescue
|
29
|
+
# do nothing
|
30
|
+
end
|
31
|
+
|
32
|
+
props = {}
|
33
|
+
%w(utm_source utm_medium utm_term utm_content utm_campaign).each do |name|
|
34
|
+
props[name.to_sym] = params[name] || landing_params[name].try(:first)
|
31
35
|
end
|
36
|
+
props
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
35
|
-
|
39
|
+
def traffic_properties
|
40
|
+
uri = URI.parse(referrer) rescue nil
|
41
|
+
{
|
42
|
+
referring_domain: uri.try(:host).try(:first, 255)
|
43
|
+
}
|
36
44
|
end
|
37
45
|
|
38
|
-
|
46
|
+
def tech_properties
|
47
|
+
if Ahoy.user_agent_parser == :device_detector
|
48
|
+
client = DeviceDetector.new(request.user_agent)
|
49
|
+
device_type =
|
50
|
+
case client.device_type
|
51
|
+
when "smartphone"
|
52
|
+
"Mobile"
|
53
|
+
when "tv"
|
54
|
+
"TV"
|
55
|
+
else
|
56
|
+
client.device_type.try(:titleize)
|
57
|
+
end
|
39
58
|
|
40
|
-
|
41
|
-
|
42
|
-
|
59
|
+
{
|
60
|
+
browser: client.name,
|
61
|
+
os: client.os_name,
|
62
|
+
device_type: device_type
|
63
|
+
}
|
64
|
+
else
|
65
|
+
raise "Add browser to your Gemfile to use legacy user agent parsing" unless defined?(Browser)
|
66
|
+
raise "Add user_agent_parser to your Gemfile to use legacy user agent parsing" unless defined?(UserAgentParser)
|
43
67
|
|
44
|
-
|
45
|
-
|
46
|
-
|
68
|
+
# cache for performance
|
69
|
+
@@user_agent_parser ||= UserAgentParser::Parser.new
|
70
|
+
|
71
|
+
user_agent = request.user_agent
|
72
|
+
agent = @@user_agent_parser.parse(user_agent)
|
73
|
+
browser = Browser.new(user_agent)
|
74
|
+
device_type =
|
75
|
+
if browser.bot?
|
76
|
+
"Bot"
|
77
|
+
elsif browser.device.tv?
|
78
|
+
"TV"
|
79
|
+
elsif browser.device.console?
|
80
|
+
"Console"
|
81
|
+
elsif browser.device.tablet?
|
82
|
+
"Tablet"
|
83
|
+
elsif browser.device.mobile?
|
84
|
+
"Mobile"
|
85
|
+
else
|
86
|
+
"Desktop"
|
87
|
+
end
|
47
88
|
|
48
|
-
|
49
|
-
|
89
|
+
{
|
90
|
+
browser: agent.name,
|
91
|
+
os: agent.os.name,
|
92
|
+
device_type: device_type
|
93
|
+
}
|
94
|
+
end
|
50
95
|
end
|
51
96
|
|
52
|
-
|
53
|
-
|
97
|
+
# masking based on Google Analytics anonymization
|
98
|
+
# https://support.google.com/analytics/answer/2763052
|
99
|
+
def ip
|
100
|
+
ip = request.remote_ip
|
101
|
+
if ip && Ahoy.mask_ips
|
102
|
+
Ahoy.mask_ip(ip)
|
103
|
+
else
|
104
|
+
ip
|
105
|
+
end
|
54
106
|
end
|
55
107
|
|
56
|
-
def
|
57
|
-
|
108
|
+
def request_properties
|
109
|
+
{
|
110
|
+
ip: ip,
|
111
|
+
user_agent: Ahoy::Utils.ensure_utf8(request.user_agent),
|
112
|
+
referrer: referrer,
|
113
|
+
landing_page: landing_page,
|
114
|
+
platform: params["platform"],
|
115
|
+
app_version: params["app_version"],
|
116
|
+
os_version: params["os_version"],
|
117
|
+
screen_height: params["screen_height"],
|
118
|
+
screen_width: params["screen_width"]
|
119
|
+
}
|
58
120
|
end
|
59
121
|
end
|
60
122
|
end
|