vwo-sdk 1.3.0 → 1.14.1
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 +5 -5
- data/lib/vwo.rb +1020 -84
- data/lib/vwo/constants.rb +64 -13
- data/lib/vwo/core/bucketer.rb +10 -14
- data/lib/vwo/core/variation_decider.rb +391 -80
- data/lib/vwo/enums.rb +113 -10
- data/lib/vwo/logger.rb +9 -3
- data/lib/vwo/schemas/settings_file.rb +1 -3
- data/lib/vwo/services/batch_events_dispatcher.rb +110 -0
- data/lib/vwo/services/batch_events_queue.rb +175 -0
- data/lib/vwo/services/event_dispatcher.rb +3 -17
- data/lib/vwo/services/hooks_manager.rb +36 -0
- data/lib/vwo/services/operand_evaluator.rb +122 -0
- data/lib/vwo/services/segment_evaluator.rb +88 -0
- data/lib/vwo/services/settings_file_manager.rb +11 -9
- data/lib/vwo/services/settings_file_processor.rb +6 -3
- data/lib/vwo/services/usage_stats.rb +29 -0
- data/lib/vwo/user_storage.rb +1 -3
- data/lib/vwo/utils/campaign.rb +151 -22
- data/lib/vwo/utils/custom_dimensions.rb +72 -0
- data/lib/vwo/utils/feature.rb +56 -0
- data/lib/vwo/utils/function.rb +6 -3
- data/lib/vwo/utils/impression.rb +76 -7
- data/lib/vwo/utils/request.rb +15 -3
- data/lib/vwo/utils/segment.rb +116 -0
- data/lib/vwo/utils/uuid.rb +3 -5
- data/lib/vwo/utils/validations.rb +96 -4
- metadata +30 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b54dc7f86b437e994c1aec92ceae2afbb5f0045deeefb2ed7feb791094e025fd
|
4
|
+
data.tar.gz: 4d087003e85fbccc63af443c7ba7e7068079df27e151e48df5f52952cd14e680
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85f28097bbc3a311354e0702f27738dc9381d37e67beba61dd7978babf81b626e1a0ccee83b503fd5e5c4fe03235cde8fd875d0643fa4e50356bc8bfd101be8c
|
7
|
+
data.tar.gz: 26c18b27e473970f0dd3ad2bf27fd4ff7e81c0aac6ee4eb84decd4f5a21db74e02082d34eb1dc74106890dd353d430bec7c77a3b90fd7fb09b9e92056072e719
|
data/lib/vwo.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2019 Wingify Software Pvt. Ltd.
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
|
15
|
+
require 'logger'
|
16
16
|
|
17
17
|
require_relative 'vwo/services/settings_file_manager'
|
18
18
|
require_relative 'vwo/services/event_dispatcher'
|
@@ -21,16 +21,22 @@ require_relative 'vwo/logger'
|
|
21
21
|
require_relative 'vwo/enums'
|
22
22
|
require_relative 'vwo/utils/campaign'
|
23
23
|
require_relative 'vwo/utils/impression'
|
24
|
+
require_relative 'vwo/utils/feature'
|
25
|
+
require_relative 'vwo/utils/custom_dimensions'
|
24
26
|
require_relative 'vwo/constants'
|
25
27
|
require_relative 'vwo/core/variation_decider'
|
26
|
-
|
28
|
+
require_relative 'vwo/services/batch_events_dispatcher'
|
29
|
+
require_relative 'vwo/services/batch_events_queue'
|
30
|
+
require_relative 'vwo/services/usage_stats'
|
27
31
|
|
28
32
|
# VWO main file
|
29
33
|
class VWO
|
30
|
-
attr_accessor :is_instance_valid
|
31
|
-
|
34
|
+
attr_accessor :is_instance_valid, :logger, :settings_file_manager, :variation_decider
|
35
|
+
attr_reader :usage_stats
|
32
36
|
include Enums
|
33
37
|
include Utils::Validations
|
38
|
+
include Utils::Feature
|
39
|
+
include Utils::CustomDimensions
|
34
40
|
include Utils::Campaign
|
35
41
|
include Utils::Impression
|
36
42
|
include CONSTANTS
|
@@ -53,14 +59,24 @@ class VWO
|
|
53
59
|
logger = nil,
|
54
60
|
user_storage = nil,
|
55
61
|
is_development_mode = false,
|
56
|
-
settings_file = nil
|
62
|
+
settings_file = nil,
|
63
|
+
options = {}
|
57
64
|
)
|
58
65
|
@account_id = account_id
|
59
66
|
@sdk_key = sdk_key
|
60
67
|
@user_storage = user_storage
|
61
68
|
@is_development_mode = is_development_mode
|
62
69
|
@logger = VWO::Logger.get_instance(logger)
|
70
|
+
@logger.instance.level = options[:log_level] if (0..5).include?(options[:log_level])
|
71
|
+
usage_stats = {}
|
72
|
+
|
73
|
+
usage_stats[:cl] = 1 if logger
|
74
|
+
usage_stats[:ll] = 1 if options[:log_level]
|
75
|
+
usage_stats[:ss] = 1 if @user_storage
|
76
|
+
usage_stats[:ig] = 1 if options.key?(:integrations)
|
77
|
+
usage_stats[:eb] = 1 if options.key?(:batch_events)
|
63
78
|
|
79
|
+
@settings_file_manager = VWO::Services::SettingsFileManager.new(@account_id, @sdk_key)
|
64
80
|
unless valid_settings_file?(get_settings(settings_file))
|
65
81
|
@logger.log(
|
66
82
|
LogLevelEnum::ERROR,
|
@@ -69,25 +85,116 @@ class VWO
|
|
69
85
|
@is_instance_valid = false
|
70
86
|
return
|
71
87
|
end
|
88
|
+
|
89
|
+
if options.key?(:should_track_returning_user)
|
90
|
+
if [true, false].include? options[:should_track_returning_user]
|
91
|
+
@should_track_returning_user = options[:should_track_returning_user]
|
92
|
+
usage_stats[:tr] = 1 if @should_track_returning_user
|
93
|
+
else
|
94
|
+
@logger.log(
|
95
|
+
LogLevelEnum::ERROR,
|
96
|
+
format(
|
97
|
+
LogMessageEnum::ErrorMessages::INVALID_TRACK_RETURNING_USER_VALUE,
|
98
|
+
file: FILE
|
99
|
+
)
|
100
|
+
)
|
101
|
+
@is_instance_valid = false
|
102
|
+
return
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@should_track_returning_user = false
|
106
|
+
end
|
107
|
+
|
108
|
+
if options.key?(:goal_type_to_track)
|
109
|
+
if GOAL_TYPES.key? options[:goal_type_to_track]
|
110
|
+
@goal_type_to_track = options[:goal_type_to_track]
|
111
|
+
usage_stats[:gt] = 1
|
112
|
+
else
|
113
|
+
@logger.log(
|
114
|
+
LogLevelEnum::ERROR,
|
115
|
+
format(
|
116
|
+
LogMessageEnum::ErrorMessages::INVALID_GOAL_TYPE,
|
117
|
+
file: FILE
|
118
|
+
)
|
119
|
+
)
|
120
|
+
@is_instance_valid = false
|
121
|
+
return
|
122
|
+
end
|
123
|
+
else
|
124
|
+
@goal_type_to_track = 'ALL'
|
125
|
+
end
|
126
|
+
|
72
127
|
@is_instance_valid = true
|
73
128
|
@config = VWO::Services::SettingsFileProcessor.new(get_settings)
|
74
129
|
|
75
130
|
@logger.log(
|
76
131
|
LogLevelEnum::DEBUG,
|
77
|
-
format(
|
132
|
+
format(
|
133
|
+
LogMessageEnum::DebugMessages::VALID_CONFIGURATION,
|
134
|
+
file: FILE
|
135
|
+
)
|
78
136
|
)
|
79
137
|
|
80
138
|
# Process the settings file
|
81
139
|
@config.process_settings_file
|
82
140
|
@settings_file = @config.get_settings_file
|
83
141
|
|
142
|
+
@usage_stats = VWO::Services::UsageStats.new(usage_stats, @is_development_mode)
|
143
|
+
|
144
|
+
if options.key?(:batch_events)
|
145
|
+
if options[:batch_events].is_a?(Hash)
|
146
|
+
unless is_valid_batch_event_settings(options[:batch_events])
|
147
|
+
@is_instance_valid = false
|
148
|
+
return
|
149
|
+
end
|
150
|
+
@batch_event_dispatcher = VWO::Services::BatchEventsDispatcher.new
|
151
|
+
def dispatcher (events, callback)
|
152
|
+
@batch_event_dispatcher.dispatch(
|
153
|
+
{
|
154
|
+
ev: events
|
155
|
+
},
|
156
|
+
callback,
|
157
|
+
{
|
158
|
+
a: @account_id,
|
159
|
+
sd: SDK_NAME,
|
160
|
+
sv: SDK_VERSION,
|
161
|
+
env: @sdk_key
|
162
|
+
}.merge(@usage_stats.usage_stats)
|
163
|
+
)
|
164
|
+
end
|
165
|
+
@batch_events_queue = VWO::Services::BatchEventsQueue.new(
|
166
|
+
options[:batch_events].merge(
|
167
|
+
{
|
168
|
+
account_id: @account_id,
|
169
|
+
dispatcher: method(:dispatcher)
|
170
|
+
}
|
171
|
+
)
|
172
|
+
)
|
173
|
+
@batch_events_queue.flush(manual: true)
|
174
|
+
@batch_events = options[:batch_events]
|
175
|
+
else
|
176
|
+
@logger.log(
|
177
|
+
LogLevelEnum::ERROR,
|
178
|
+
format(
|
179
|
+
LogMessageEnum::ErrorMessages::EVENT_BATCHING_NOT_OBJECT,
|
180
|
+
file: FILE
|
181
|
+
)
|
182
|
+
)
|
183
|
+
@is_instance_valid = false
|
184
|
+
return
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
84
188
|
# Assign VariationDecider to VWO
|
85
|
-
@variation_decider = VWO::Core::VariationDecider.new(@settings_file, user_storage)
|
189
|
+
@variation_decider = VWO::Core::VariationDecider.new(@settings_file, user_storage, options)
|
86
190
|
|
87
191
|
if is_development_mode
|
88
192
|
@logger.log(
|
89
193
|
LogLevelEnum::DEBUG,
|
90
|
-
format(
|
194
|
+
format(
|
195
|
+
LogMessageEnum::DebugMessages::SET_DEVELOPMENT_MODE,
|
196
|
+
file: FILE
|
197
|
+
)
|
91
198
|
)
|
92
199
|
end
|
93
200
|
# Assign event dispatcher
|
@@ -96,7 +203,10 @@ class VWO
|
|
96
203
|
# Successfully initialized VWO SDK
|
97
204
|
@logger.log(
|
98
205
|
LogLevelEnum::DEBUG,
|
99
|
-
format(
|
206
|
+
format(
|
207
|
+
LogMessageEnum::DebugMessages::SDK_INITIALIZED,
|
208
|
+
file: FILE
|
209
|
+
)
|
100
210
|
)
|
101
211
|
end
|
102
212
|
|
@@ -104,9 +214,55 @@ class VWO
|
|
104
214
|
|
105
215
|
# VWO get_settings method to get settings for a particular account_id
|
106
216
|
def get_settings(settings_file = nil)
|
107
|
-
@
|
108
|
-
settings_file ||
|
109
|
-
@
|
217
|
+
@settings_file ||=
|
218
|
+
settings_file || @settings_file_manager.get_settings_file
|
219
|
+
@settings_file
|
220
|
+
end
|
221
|
+
|
222
|
+
# This API method: fetch the latest settings file and update it
|
223
|
+
|
224
|
+
# VWO get_settings method to get settings for a particular account_id
|
225
|
+
def get_and_update_settings_file
|
226
|
+
|
227
|
+
unless @is_instance_valid
|
228
|
+
@logger.log(
|
229
|
+
LogLevelEnum::ERROR,
|
230
|
+
format(
|
231
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
232
|
+
file: FILE,
|
233
|
+
api_name: ApiMethods.GET_AND_UPDATE_SETTINGS_FILE
|
234
|
+
)
|
235
|
+
)
|
236
|
+
return
|
237
|
+
end
|
238
|
+
|
239
|
+
latest_settings = @settings_file_manager.get_settings_file(true)
|
240
|
+
latest_settings = JSON.parse(latest_settings)
|
241
|
+
if latest_settings == @settings_file
|
242
|
+
@logger.log(
|
243
|
+
LogLevelEnum::INFO,
|
244
|
+
format(
|
245
|
+
LogMessageEnum::InfoMessages::SETTINGS_NOT_UPDATED,
|
246
|
+
api_name: ApiMethods::GET_AND_UPDATE_SETTINGS_FILE,
|
247
|
+
file: FILE
|
248
|
+
)
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
@config.update_settings_file(latest_settings)
|
253
|
+
@settings_file = @config.get_settings_file
|
254
|
+
@settings_file
|
255
|
+
rescue StandardError => e
|
256
|
+
@logger.log(
|
257
|
+
LogLevelEnum::ERROR,
|
258
|
+
format(
|
259
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
260
|
+
file: FILE,
|
261
|
+
api_name: ApiMethods::GET_AND_UPDATE_SETTINGS_FILE,
|
262
|
+
exception: e
|
263
|
+
)
|
264
|
+
)
|
265
|
+
nil
|
110
266
|
end
|
111
267
|
|
112
268
|
# This API method: Gets the variation assigned for the user
|
@@ -122,23 +278,38 @@ class VWO
|
|
122
278
|
#
|
123
279
|
# @param[String] :campaign_key Unique campaign key
|
124
280
|
# @param[String] :user_id ID assigned to a user
|
281
|
+
# @param[Hash] :options Options for custom variables required for segmentation
|
125
282
|
# @return[String|None] If variation is assigned then variation-name
|
126
283
|
# otherwise null in case of user not becoming part
|
127
284
|
|
128
|
-
def activate(campaign_key, user_id)
|
129
|
-
|
130
|
-
unless valid_string?(campaign_key) && valid_string?(user_id)
|
285
|
+
def activate(campaign_key, user_id, options = {})
|
286
|
+
unless @is_instance_valid
|
131
287
|
@logger.log(
|
132
288
|
LogLevelEnum::ERROR,
|
133
|
-
format(
|
289
|
+
format(
|
290
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
291
|
+
file: FILE,
|
292
|
+
api_name: ApiMethods::ACTIVATE
|
293
|
+
)
|
134
294
|
)
|
135
295
|
return
|
136
296
|
end
|
137
297
|
|
138
|
-
|
298
|
+
# Retrieve custom variables
|
299
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
300
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
301
|
+
|
302
|
+
should_track_returning_user = get_should_track_returning_user(options)
|
303
|
+
# Validate input parameters
|
304
|
+
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
305
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user)
|
139
306
|
@logger.log(
|
140
307
|
LogLevelEnum::ERROR,
|
141
|
-
format(
|
308
|
+
format(
|
309
|
+
LogMessageEnum::ErrorMessages::ACTIVATE_API_MISSING_PARAMS,
|
310
|
+
api_name: ApiMethods::ACTIVATE,
|
311
|
+
file: FILE
|
312
|
+
)
|
142
313
|
)
|
143
314
|
return
|
144
315
|
end
|
@@ -151,36 +322,122 @@ class VWO
|
|
151
322
|
# Log Campaign as invalid
|
152
323
|
@logger.log(
|
153
324
|
LogLevelEnum::ERROR,
|
154
|
-
format(
|
325
|
+
format(
|
326
|
+
LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
|
327
|
+
file: FILE,
|
328
|
+
campaign_key: campaign_key,
|
329
|
+
api_name: ApiMethods::ACTIVATE
|
330
|
+
)
|
331
|
+
)
|
332
|
+
return
|
333
|
+
end
|
334
|
+
|
335
|
+
# Get campaign type
|
336
|
+
campaign_type = campaign['type']
|
337
|
+
|
338
|
+
# Validate valid api call
|
339
|
+
if campaign_type != CampaignTypes::VISUAL_AB
|
340
|
+
@logger.log(
|
341
|
+
LogLevelEnum::ERROR,
|
342
|
+
format(
|
343
|
+
LogMessageEnum::ErrorMessages::INVALID_API,
|
344
|
+
file: FILE,
|
345
|
+
api_name: ApiMethods::ACTIVATE,
|
346
|
+
user_id: user_id,
|
347
|
+
campaign_key: campaign_key,
|
348
|
+
campaign_type: campaign_type
|
349
|
+
)
|
155
350
|
)
|
156
351
|
return
|
157
352
|
end
|
158
353
|
|
159
354
|
# Once the matching RUNNING campaign is found, assign the
|
160
355
|
# deterministic variation to the user_id provided
|
161
|
-
|
356
|
+
|
357
|
+
variation = @variation_decider.get_variation(
|
162
358
|
user_id,
|
163
|
-
campaign
|
359
|
+
campaign,
|
360
|
+
ApiMethods::ACTIVATE,
|
361
|
+
campaign_key,
|
362
|
+
custom_variables,
|
363
|
+
variation_targeting_variables
|
164
364
|
)
|
165
365
|
|
166
366
|
# Check if variation_name has been assigned
|
167
|
-
|
367
|
+
if variation.nil?
|
168
368
|
@logger.log(
|
169
369
|
LogLevelEnum::INFO,
|
170
|
-
format(
|
370
|
+
format(
|
371
|
+
LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY,
|
372
|
+
file: FILE,
|
373
|
+
user_id: user_id,
|
374
|
+
campaign_key: campaign_key
|
375
|
+
)
|
171
376
|
)
|
172
377
|
return
|
173
378
|
end
|
174
379
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
380
|
+
if is_eligible_to_send_impression(should_track_returning_user)
|
381
|
+
if defined?(@batch_events)
|
382
|
+
impression = create_bulk_event_impression(
|
383
|
+
@settings_file,
|
384
|
+
campaign['id'],
|
385
|
+
variation['id'],
|
386
|
+
user_id
|
387
|
+
)
|
388
|
+
@batch_events_queue.enqueue(impression)
|
389
|
+
else
|
390
|
+
# Variation found, dispatch it to server
|
391
|
+
impression = create_impression(
|
392
|
+
@settings_file,
|
393
|
+
campaign['id'],
|
394
|
+
variation['id'],
|
395
|
+
user_id,
|
396
|
+
@sdk_key,
|
397
|
+
nil, # goal_id
|
398
|
+
nil, # revenue
|
399
|
+
usage_stats: @usage_stats.usage_stats
|
400
|
+
)
|
401
|
+
if @event_dispatcher.dispatch(impression)
|
402
|
+
@logger.log(
|
403
|
+
LogLevelEnum::INFO,
|
404
|
+
format(
|
405
|
+
LogMessageEnum::InfoMessages::IMPRESSION_SUCCESS,
|
406
|
+
file: FILE,
|
407
|
+
sdk_key: @sdk_key,
|
408
|
+
account_id: @account_id,
|
409
|
+
campaign_id: campaign['id'],
|
410
|
+
variation_id: variation['id'],
|
411
|
+
end_point: EVENTS::TRACK_USER
|
412
|
+
)
|
413
|
+
)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
variation['name']
|
417
|
+
else
|
418
|
+
@logger.log(
|
419
|
+
LogLevelEnum::INFO,
|
420
|
+
format(
|
421
|
+
LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
|
422
|
+
file: FILE,
|
423
|
+
user_id: user_id,
|
424
|
+
campaign_key: campaign_key,
|
425
|
+
api_name: ApiMethods::ACTIVATE
|
426
|
+
)
|
427
|
+
)
|
428
|
+
nil
|
429
|
+
end
|
430
|
+
rescue StandardError => e
|
431
|
+
@logger.log(
|
432
|
+
LogLevelEnum::ERROR,
|
433
|
+
format(
|
434
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
435
|
+
file: FILE,
|
436
|
+
api_name: ApiMethods::ACTIVATE,
|
437
|
+
exception: e
|
438
|
+
)
|
181
439
|
)
|
182
|
-
|
183
|
-
variation_name
|
440
|
+
nil
|
184
441
|
end
|
185
442
|
|
186
443
|
# This API method: Gets the variation name assigned for the
|
@@ -195,25 +452,37 @@ class VWO
|
|
195
452
|
#
|
196
453
|
# @param[String] :campaign_key Unique campaign key
|
197
454
|
# @param[String] :user_id ID assigned to a user
|
455
|
+
# @param[Hash] :options Options for custom variables required for segmentation
|
198
456
|
#
|
199
457
|
# @@return[String|Nil] If variation is assigned then variation-name
|
200
458
|
# Otherwise null in case of user not becoming part
|
201
459
|
#
|
202
|
-
def get_variation_name(campaign_key, user_id)
|
203
|
-
|
204
|
-
unless valid_string?(campaign_key) && valid_string?(user_id)
|
205
|
-
# log invalid params
|
460
|
+
def get_variation_name(campaign_key, user_id, options = {})
|
461
|
+
unless @is_instance_valid
|
206
462
|
@logger.log(
|
207
463
|
LogLevelEnum::ERROR,
|
208
|
-
format(
|
464
|
+
format(
|
465
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
466
|
+
file: FILE,
|
467
|
+
api_name: ApiMethods::GET_VARIATION_NAME
|
468
|
+
)
|
209
469
|
)
|
210
470
|
return
|
211
471
|
end
|
472
|
+
# Retrieve custom variables
|
473
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
474
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
212
475
|
|
213
|
-
|
476
|
+
# Validate input parameters
|
477
|
+
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
478
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
214
479
|
@logger.log(
|
215
480
|
LogLevelEnum::ERROR,
|
216
|
-
format(
|
481
|
+
format(
|
482
|
+
LogMessageEnum::ErrorMessages::GET_VARIATION_NAME_API_INVALID_PARAMS,
|
483
|
+
api_name: ApiMethods::GET_VARIATION_NAME,
|
484
|
+
file: FILE
|
485
|
+
)
|
217
486
|
)
|
218
487
|
return
|
219
488
|
end
|
@@ -225,27 +494,62 @@ class VWO
|
|
225
494
|
if campaign.nil? || campaign['status'] != STATUS_RUNNING
|
226
495
|
@logger.log(
|
227
496
|
LogLevelEnum::ERROR,
|
228
|
-
format(
|
497
|
+
format(
|
498
|
+
LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
|
499
|
+
file: FILE,
|
500
|
+
campaign_key: campaign_key,
|
501
|
+
api_name: ApiMethods::GET_VARIATION_NAME
|
502
|
+
)
|
229
503
|
)
|
230
504
|
return
|
231
505
|
end
|
232
506
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
507
|
+
campaign_type = campaign['type']
|
508
|
+
|
509
|
+
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
510
|
+
@logger.log(
|
511
|
+
LogLevelEnum::ERROR,
|
512
|
+
format(
|
513
|
+
LogMessageEnum::ErrorMessages.INVALID_API,
|
514
|
+
file: FILE,
|
515
|
+
api_name: ApiMethods::GET_VARIATION_NAME,
|
516
|
+
user_id: user_id,
|
517
|
+
campaign_key: campaign_key,
|
518
|
+
campaign_type: campaign_type
|
519
|
+
)
|
520
|
+
)
|
521
|
+
return
|
522
|
+
end
|
523
|
+
|
524
|
+
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::GET_VARIATION_NAME, campaign_key, custom_variables, variation_targeting_variables)
|
237
525
|
|
238
526
|
# Check if variation_name has been assigned
|
239
|
-
unless valid_value?(
|
527
|
+
unless valid_value?(variation)
|
240
528
|
# log invalid variation key
|
241
529
|
@logger.log(
|
242
530
|
LogLevelEnum::INFO,
|
243
|
-
format(
|
531
|
+
format(
|
532
|
+
LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY,
|
533
|
+
file: FILE,
|
534
|
+
user_id: user_id,
|
535
|
+
campaign_key: campaign_key
|
536
|
+
)
|
244
537
|
)
|
245
538
|
return
|
246
539
|
end
|
247
540
|
|
248
|
-
|
541
|
+
variation['name']
|
542
|
+
rescue StandardError => e
|
543
|
+
@logger.log(
|
544
|
+
LogLevelEnum::ERROR,
|
545
|
+
format(
|
546
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
547
|
+
file: FILE,
|
548
|
+
api_name: ApiMethods::GET_VARIATION_NAME,
|
549
|
+
exception: e
|
550
|
+
)
|
551
|
+
)
|
552
|
+
nil
|
249
553
|
end
|
250
554
|
|
251
555
|
# This API method: Marks the conversion of the campaign
|
@@ -258,30 +562,265 @@ class VWO
|
|
258
562
|
#
|
259
563
|
# @param[String] :campaign_key Unique campaign key
|
260
564
|
# @param[String] :user_id ID assigned to a user
|
261
|
-
# @param[String] :goal_identifier
|
262
|
-
# @param[
|
565
|
+
# @param[String] :goal_identifier Unique campaign's goal identifier
|
566
|
+
# @param[Hash] :options Contains revenue value and custom variables
|
567
|
+
# @param[Numeric|String] :revenue_value It is the revenue generated on triggering the goal
|
263
568
|
#
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
569
|
+
|
570
|
+
def track(campaign_key, user_id, goal_identifier, options = {})
|
571
|
+
unless @is_instance_valid
|
572
|
+
@logger.log(
|
573
|
+
LogLevelEnum::ERROR,
|
574
|
+
format(
|
575
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
576
|
+
file: FILE,
|
577
|
+
api_name: ApiMethods::TRACK
|
578
|
+
)
|
579
|
+
)
|
580
|
+
return false
|
269
581
|
end
|
270
582
|
|
583
|
+
revenue_value = options['revenue_value'] || options[:revenue_value]
|
584
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
585
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
586
|
+
should_track_returning_user = get_should_track_returning_user(options)
|
587
|
+
goal_type_to_track = get_goal_type_to_track(options)
|
588
|
+
|
271
589
|
# Check for valid args
|
272
|
-
unless valid_string?(campaign_key) && valid_string?(user_id) && valid_string?(goal_identifier)
|
590
|
+
unless (valid_string?(campaign_key) || campaign_key.is_a?(Array) || campaign_key.nil?) && valid_string?(user_id) && valid_string?(goal_identifier) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
591
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user) && (GOAL_TYPES.key? (goal_type_to_track))
|
273
592
|
# log invalid params
|
274
593
|
@logger.log(
|
275
594
|
LogLevelEnum::ERROR,
|
276
|
-
format(
|
595
|
+
format(
|
596
|
+
LogMessageEnum::ErrorMessages::TRACK_API_INVALID_PARAMS,
|
597
|
+
file: FILE,
|
598
|
+
api_name: ApiMethods::TRACK
|
599
|
+
)
|
277
600
|
)
|
278
601
|
return false
|
279
602
|
end
|
280
603
|
|
604
|
+
# Get campaigns settings
|
605
|
+
campaigns = get_campaigns(@settings_file, campaign_key, goal_identifier, goal_type_to_track)
|
606
|
+
|
607
|
+
# Validate campaign
|
608
|
+
if campaigns.nil?
|
609
|
+
return nil
|
610
|
+
end
|
611
|
+
|
612
|
+
result = {}
|
613
|
+
campaigns.each do |campaign|
|
614
|
+
campaign_type = campaign['type']
|
615
|
+
|
616
|
+
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
617
|
+
@logger.log(
|
618
|
+
LogLevelEnum::ERROR,
|
619
|
+
format(
|
620
|
+
LogMessageEnum::ErrorMessages::INVALID_API,
|
621
|
+
file: FILE,
|
622
|
+
api_name: ApiMethods::TRACK,
|
623
|
+
user_id: user_id,
|
624
|
+
campaign_key: campaign['key'],
|
625
|
+
campaign_type: campaign_type
|
626
|
+
)
|
627
|
+
)
|
628
|
+
result[campaign['key']] = false
|
629
|
+
next
|
630
|
+
end
|
631
|
+
|
632
|
+
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::TRACK, campaign['key'], custom_variables, variation_targeting_variables, goal_identifier)
|
633
|
+
|
634
|
+
if variation
|
635
|
+
goal = get_campaign_goal(campaign, goal_identifier)
|
636
|
+
if goal.nil? || !goal["id"]
|
637
|
+
@logger.log(
|
638
|
+
LogLevelEnum::ERROR,
|
639
|
+
format(
|
640
|
+
LogMessageEnum::ErrorMessages::TRACK_API_GOAL_NOT_FOUND,
|
641
|
+
file: FILE,
|
642
|
+
goal_identifier: goal_identifier,
|
643
|
+
user_id: user_id,
|
644
|
+
campaign_key: campaign['key'],
|
645
|
+
api_name: ApiMethods::TRACK
|
646
|
+
)
|
647
|
+
)
|
648
|
+
result[campaign['key']] = false
|
649
|
+
next
|
650
|
+
elsif goal['type'] == GoalTypes::REVENUE && !valid_value?(revenue_value)
|
651
|
+
@logger.log(
|
652
|
+
LogLevelEnum::ERROR,
|
653
|
+
format(
|
654
|
+
LogMessageEnum::ErrorMessages::TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL,
|
655
|
+
file: FILE,
|
656
|
+
user_id: user_id,
|
657
|
+
goal_identifier: goal_identifier,
|
658
|
+
campaign_key: campaign['key'],
|
659
|
+
api_name: ApiMethods::TRACK
|
660
|
+
)
|
661
|
+
)
|
662
|
+
result[campaign['key']] = false
|
663
|
+
next
|
664
|
+
elsif goal['type'] == GoalTypes::CUSTOM
|
665
|
+
revenue_value = nil
|
666
|
+
end
|
667
|
+
|
668
|
+
if variation['goal_identifier']
|
669
|
+
identifiers = variation['goal_identifier'].split(VWO_DELIMITER)
|
670
|
+
else
|
671
|
+
variation['goal_identifier'] = ''
|
672
|
+
identifiers = []
|
673
|
+
end
|
674
|
+
|
675
|
+
if !identifiers.include? goal_identifier
|
676
|
+
updated_goal_identifier = variation['goal_identifier']
|
677
|
+
updated_goal_identifier += VWO_DELIMITER + goal_identifier
|
678
|
+
@variation_decider.save_user_storage(user_id, campaign['key'], variation['name'], updated_goal_identifier) if variation['name']
|
679
|
+
# set variation at user storage
|
680
|
+
elsif !should_track_returning_user
|
681
|
+
@logger.log(
|
682
|
+
LogLevelEnum::INFO,
|
683
|
+
format(
|
684
|
+
LogMessageEnum::InfoMessages::GOAL_ALREADY_TRACKED,
|
685
|
+
file: FILE,
|
686
|
+
user_id: user_id,
|
687
|
+
campaign_key: campaign['key'],
|
688
|
+
goal_identifier: goal_identifier,
|
689
|
+
api_name: ApiMethods::TRACK
|
690
|
+
)
|
691
|
+
)
|
692
|
+
result[campaign['key']] = false
|
693
|
+
next
|
694
|
+
end
|
695
|
+
|
696
|
+
if defined?(@batch_events)
|
697
|
+
impression = create_bulk_event_impression(
|
698
|
+
@settings_file,
|
699
|
+
campaign['id'],
|
700
|
+
variation['id'],
|
701
|
+
user_id,
|
702
|
+
goal['id'],
|
703
|
+
revenue_value
|
704
|
+
)
|
705
|
+
@batch_events_queue.enqueue(impression)
|
706
|
+
else
|
707
|
+
impression = create_impression(
|
708
|
+
@settings_file,
|
709
|
+
campaign['id'],
|
710
|
+
variation['id'],
|
711
|
+
user_id,
|
712
|
+
@sdk_key,
|
713
|
+
goal['id'],
|
714
|
+
revenue_value
|
715
|
+
)
|
716
|
+
if @event_dispatcher.dispatch(impression)
|
717
|
+
@logger.log(
|
718
|
+
LogLevelEnum::INFO,
|
719
|
+
format(
|
720
|
+
LogMessageEnum::InfoMessages::IMPRESSION_SUCCESS,
|
721
|
+
file: FILE,
|
722
|
+
sdk_key: @sdk_key,
|
723
|
+
account_id: @account_id,
|
724
|
+
campaign_id: campaign['id'],
|
725
|
+
variation_id: variation['id'],
|
726
|
+
end_point: EVENTS::TRACK_GOAL
|
727
|
+
)
|
728
|
+
)
|
729
|
+
@logger.log(
|
730
|
+
LogLevelEnum::INFO,
|
731
|
+
format(
|
732
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
|
733
|
+
file: FILE,
|
734
|
+
sdk_key: @sdk_key,
|
735
|
+
campaign_id: impression[:experiment_id],
|
736
|
+
account_id: impression[:account_id],
|
737
|
+
variation_id: impression[:combination]
|
738
|
+
)
|
739
|
+
)
|
740
|
+
end
|
741
|
+
end
|
742
|
+
result[campaign['key']] = true
|
743
|
+
next
|
744
|
+
end
|
745
|
+
result[campaign['key']] = false
|
746
|
+
rescue StandardError => e
|
747
|
+
@logger.log(
|
748
|
+
LogLevelEnum::ERROR,
|
749
|
+
format(
|
750
|
+
e.message,
|
751
|
+
file: FILE,
|
752
|
+
exception: e
|
753
|
+
)
|
754
|
+
)
|
755
|
+
end
|
756
|
+
|
757
|
+
if result.length() == 0
|
758
|
+
return nil
|
759
|
+
end
|
760
|
+
|
761
|
+
result
|
762
|
+
rescue StandardError => e
|
763
|
+
@logger.log(
|
764
|
+
LogLevelEnum::ERROR,
|
765
|
+
format(
|
766
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
767
|
+
file: FILE,
|
768
|
+
api_name: ApiMethods::TRACK,
|
769
|
+
exception: e
|
770
|
+
)
|
771
|
+
)
|
772
|
+
false
|
773
|
+
end
|
774
|
+
|
775
|
+
# This API method: Identifies whether the user becomes a part of feature rollout/test or not.
|
776
|
+
# 1. Validates the arguments being passed
|
777
|
+
# 2. Checks if user is eligible to get bucketed into the feature test/rollout,
|
778
|
+
# 3. Assigns the deterministic variation to the user(based on userId),
|
779
|
+
# If user becomes part of feature test/rollout
|
780
|
+
# If UserStorage is used, it will look into it for the variation and if found, no further processing is done
|
781
|
+
#
|
782
|
+
# @param[String] :campaign_key Unique campaign key
|
783
|
+
# @param[String] :user_id ID assigned to a user
|
784
|
+
# @param[Hash] :custom_variables Pass it through options as custom_variables={}
|
785
|
+
#
|
786
|
+
# @return[Boolean] true if user becomes part of feature test/rollout, otherwise false.
|
787
|
+
|
788
|
+
def feature_enabled?(campaign_key, user_id, options = {})
|
281
789
|
unless @is_instance_valid
|
282
790
|
@logger.log(
|
283
791
|
LogLevelEnum::ERROR,
|
284
|
-
format(
|
792
|
+
format(
|
793
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
794
|
+
file: FILE,
|
795
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
796
|
+
)
|
797
|
+
)
|
798
|
+
return false
|
799
|
+
end
|
800
|
+
|
801
|
+
# Retrieve custom variables
|
802
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
803
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
804
|
+
should_track_returning_user = get_should_track_returning_user(options)
|
805
|
+
@logger.log(
|
806
|
+
LogLevelEnum::INFO,
|
807
|
+
format(
|
808
|
+
LogMessageEnum::InfoMessages::API_CALLED,
|
809
|
+
file: FILE,
|
810
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED,
|
811
|
+
user_id: user_id
|
812
|
+
)
|
813
|
+
)
|
814
|
+
# Validate input parameters
|
815
|
+
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
816
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user)
|
817
|
+
@logger.log(
|
818
|
+
LogLevelEnum::ERROR,
|
819
|
+
format(
|
820
|
+
LogMessageEnum::ErrorMessages::IS_FEATURE_ENABLED_API_INVALID_PARAMS,
|
821
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED,
|
822
|
+
file: FILE
|
823
|
+
)
|
285
824
|
)
|
286
825
|
return false
|
287
826
|
end
|
@@ -290,59 +829,456 @@ class VWO
|
|
290
829
|
campaign = get_campaign(@settings_file, campaign_key)
|
291
830
|
|
292
831
|
# Validate campaign
|
293
|
-
|
832
|
+
unless campaign && campaign['status'] == STATUS_RUNNING
|
294
833
|
# log error
|
295
834
|
@logger.log(
|
296
835
|
LogLevelEnum::ERROR,
|
297
|
-
format(
|
836
|
+
format(
|
837
|
+
LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
|
838
|
+
file: FILE,
|
839
|
+
campaign_key: campaign_key,
|
840
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
841
|
+
)
|
298
842
|
)
|
299
843
|
return false
|
300
844
|
end
|
301
845
|
|
302
|
-
|
303
|
-
|
846
|
+
# Validate campaign_type
|
847
|
+
campaign_type = campaign['type']
|
304
848
|
|
305
|
-
if
|
306
|
-
|
849
|
+
if campaign_type == CampaignTypes::VISUAL_AB
|
850
|
+
@logger.log(
|
851
|
+
LogLevelEnum::ERROR,
|
852
|
+
format(
|
853
|
+
LogMessageEnum::ErrorMessages::INVALID_API,
|
854
|
+
file: FILE,
|
855
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED,
|
856
|
+
user_id: user_id,
|
857
|
+
campaign_key: campaign_key,
|
858
|
+
campaign_type: campaign_type
|
859
|
+
)
|
860
|
+
)
|
861
|
+
return false
|
862
|
+
end
|
863
|
+
|
864
|
+
# Get variation
|
865
|
+
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::IS_FEATURE_ENABLED, campaign_key, custom_variables, variation_targeting_variables)
|
866
|
+
|
867
|
+
# If no variation, did not become part of feature_test/rollout
|
868
|
+
return false unless variation
|
869
|
+
|
870
|
+
# if campaign type is feature_test Send track call to server
|
871
|
+
if campaign_type == CampaignTypes::FEATURE_TEST
|
872
|
+
if is_eligible_to_send_impression(should_track_returning_user)
|
873
|
+
if defined?(@batch_events)
|
874
|
+
impression = create_bulk_event_impression(
|
875
|
+
@settings_file,
|
876
|
+
campaign['id'],
|
877
|
+
variation['id'],
|
878
|
+
user_id
|
879
|
+
)
|
880
|
+
@batch_events_queue.enqueue(impression)
|
881
|
+
else
|
882
|
+
impression = create_impression(
|
883
|
+
@settings_file,
|
884
|
+
campaign['id'],
|
885
|
+
variation['id'],
|
886
|
+
user_id,
|
887
|
+
@sdk_key,
|
888
|
+
goal_id: nil,
|
889
|
+
revenue: nil,
|
890
|
+
usage_stats: @usage_stats.usage_stats
|
891
|
+
)
|
307
892
|
|
308
|
-
|
893
|
+
@event_dispatcher.dispatch(impression)
|
894
|
+
@logger.log(
|
895
|
+
LogLevelEnum::INFO,
|
896
|
+
format(
|
897
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
|
898
|
+
file: FILE,
|
899
|
+
campaign_id: impression[:experiment_id],
|
900
|
+
sdk_key: @sdk_key,
|
901
|
+
account_id: impression[:account_id],
|
902
|
+
variation_id: impression[:combination]
|
903
|
+
)
|
904
|
+
)
|
905
|
+
end
|
906
|
+
result = variation['isFeatureEnabled']
|
907
|
+
if result
|
908
|
+
@logger.log(
|
909
|
+
LogLevelEnum::INFO,
|
910
|
+
format(
|
911
|
+
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
912
|
+
file: FILE,
|
913
|
+
user_id: user_id,
|
914
|
+
feature_key: campaign_key,
|
915
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
916
|
+
)
|
917
|
+
)
|
918
|
+
else
|
919
|
+
@logger.log(
|
920
|
+
LogLevelEnum::INFO,
|
921
|
+
format(
|
922
|
+
LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
|
923
|
+
file: FILE,
|
924
|
+
user_id: user_id,
|
925
|
+
feature_key: campaign_key,
|
926
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
927
|
+
)
|
928
|
+
)
|
929
|
+
end
|
930
|
+
return result
|
931
|
+
else
|
309
932
|
@logger.log(
|
310
|
-
LogLevelEnum::
|
933
|
+
LogLevelEnum::INFO,
|
934
|
+
format(
|
935
|
+
LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
|
936
|
+
file: FILE,
|
937
|
+
user_id: user_id,
|
938
|
+
campaign_key: campaign_key,
|
939
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
940
|
+
)
|
941
|
+
)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
true
|
945
|
+
rescue StandardError => e
|
946
|
+
@logger.log(
|
947
|
+
LogLevelEnum::ERROR,
|
948
|
+
format(
|
949
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
950
|
+
file: FILE,
|
951
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED,
|
952
|
+
exception: e
|
953
|
+
)
|
954
|
+
)
|
955
|
+
false
|
956
|
+
end
|
957
|
+
|
958
|
+
# Returns the feature variable corresponding to the variable_key
|
959
|
+
# passed. It typecasts the value to the corresponding value type
|
960
|
+
# found in settings_file
|
961
|
+
#
|
962
|
+
# 1. Validates the arguments being passed
|
963
|
+
# 2. Checks if user is eligible to get bucketed into the feature test/rollout,
|
964
|
+
# 3. Assigns the deterministic variation to the user(based on userId),
|
965
|
+
# If user becomes part of campaign
|
966
|
+
# If UserStorage is used, it will look into it for the variation and if found, no further processing is done
|
967
|
+
# 4. Retrieves the corresponding variable from variation assigned.
|
968
|
+
#
|
969
|
+
# @param[String] :campaign_key Unique campaign key
|
970
|
+
# @param[String] :variable_key Variable key
|
971
|
+
# @param[String] :user_id ID assigned to a user
|
972
|
+
# @param[Hash] :custom_variables Pass it through options as custom_variables={}
|
973
|
+
#
|
974
|
+
# @return[Boolean, String, Integer, Float, nil) If variation is assigned then variable corresponding to variation assigned else nil
|
975
|
+
#
|
976
|
+
|
977
|
+
def get_feature_variable_value(campaign_key, variable_key, user_id, options = {})
|
978
|
+
unless @is_instance_valid
|
979
|
+
@logger.log(
|
980
|
+
LogLevelEnum::ERROR,
|
981
|
+
format(
|
982
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
983
|
+
file: FILE,
|
984
|
+
api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
|
985
|
+
)
|
986
|
+
)
|
987
|
+
return
|
988
|
+
end
|
989
|
+
|
990
|
+
# Retrieve custom variables
|
991
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
992
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
993
|
+
|
994
|
+
unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
|
995
|
+
(custom_variables.nil? || valid_hash?(custom_variables)) && (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
996
|
+
@logger.log(
|
997
|
+
LogLevelEnum::ERROR,
|
998
|
+
format(
|
999
|
+
LogMessageEnum::ErrorMessages::GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS,
|
1000
|
+
file: FILE,
|
1001
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
1002
|
+
)
|
1003
|
+
)
|
1004
|
+
return
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
# Get the campaign settings
|
1008
|
+
campaign = get_campaign(@settings_file, campaign_key)
|
1009
|
+
|
1010
|
+
# Validate campaign
|
1011
|
+
unless campaign && campaign['status'] == STATUS_RUNNING
|
1012
|
+
# log error
|
1013
|
+
@logger.log(
|
1014
|
+
LogLevelEnum::ERROR,
|
1015
|
+
format(
|
1016
|
+
LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
|
1017
|
+
file: FILE,
|
1018
|
+
campaign_key: campaign_key,
|
1019
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
1020
|
+
)
|
1021
|
+
)
|
1022
|
+
return
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
campaign_type = campaign['type']
|
1026
|
+
|
1027
|
+
if campaign_type == CampaignTypes::VISUAL_AB
|
1028
|
+
@logger.log(
|
1029
|
+
LogLevelEnum::ERROR,
|
1030
|
+
format(
|
1031
|
+
LogMessageEnum::ErrorMessages::INVALID_API,
|
1032
|
+
file: FILE,
|
1033
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE,
|
1034
|
+
campaign_key: campaign_key,
|
1035
|
+
campaign_type: campaign_type,
|
1036
|
+
user_id: user_id
|
1037
|
+
)
|
1038
|
+
)
|
1039
|
+
return
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::GET_FEATURE_VARIABLE_VALUE, campaign_key, custom_variables, variation_targeting_variables)
|
1043
|
+
|
1044
|
+
# Check if variation has been assigned to user
|
1045
|
+
return unless variation
|
1046
|
+
|
1047
|
+
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
1048
|
+
variables = campaign['variables']
|
1049
|
+
elsif campaign_type == CampaignTypes::FEATURE_TEST
|
1050
|
+
if !variation['isFeatureEnabled']
|
1051
|
+
@logger.log(
|
1052
|
+
LogLevelEnum::INFO,
|
311
1053
|
format(
|
312
|
-
LogMessageEnum::
|
313
|
-
file: FILE,
|
1054
|
+
LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
|
1055
|
+
file: FILE,
|
1056
|
+
feature_key: campaign_key,
|
314
1057
|
user_id: user_id,
|
315
|
-
|
1058
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
316
1059
|
)
|
317
1060
|
)
|
318
|
-
|
319
|
-
|
1061
|
+
variation = get_control_variation(campaign)
|
1062
|
+
else
|
320
1063
|
@logger.log(
|
321
|
-
LogLevelEnum::
|
1064
|
+
LogLevelEnum::INFO,
|
322
1065
|
format(
|
323
|
-
LogMessageEnum::
|
1066
|
+
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
324
1067
|
file: FILE,
|
1068
|
+
feature_key: campaign_key,
|
325
1069
|
user_id: user_id,
|
326
|
-
|
327
|
-
campaign_key: campaign_key
|
1070
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
328
1071
|
)
|
329
1072
|
)
|
330
|
-
return false
|
331
1073
|
end
|
1074
|
+
variables = variation['variables']
|
1075
|
+
end
|
1076
|
+
variable = get_variable(variables, variable_key)
|
1077
|
+
|
1078
|
+
unless variable
|
1079
|
+
# Log variable not found
|
1080
|
+
@logger.log(
|
1081
|
+
LogLevelEnum::ERROR,
|
1082
|
+
format(
|
1083
|
+
LogMessageEnum::ErrorMessages::VARIABLE_NOT_FOUND,
|
1084
|
+
file: FILE,
|
1085
|
+
variable_key: variable_key,
|
1086
|
+
campaign_key: campaign_key,
|
1087
|
+
campaign_type: campaign_type,
|
1088
|
+
user_id: user_id,
|
1089
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
1090
|
+
)
|
1091
|
+
)
|
1092
|
+
return
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
@logger.log(
|
1096
|
+
LogLevelEnum::INFO,
|
1097
|
+
format(
|
1098
|
+
LogMessageEnum::InfoMessages::VARIABLE_FOUND,
|
1099
|
+
file: FILE,
|
1100
|
+
variable_key: variable_key,
|
1101
|
+
variable_value: variable['value'],
|
1102
|
+
campaign_key: campaign_key,
|
1103
|
+
campaign_type: campaign_type,
|
1104
|
+
user_id: user_id,
|
1105
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
1106
|
+
)
|
1107
|
+
)
|
1108
|
+
get_type_casted_feature_value(variable['value'], variable['type'])
|
1109
|
+
rescue StandardError => e
|
1110
|
+
@logger.log(
|
1111
|
+
LogLevelEnum::ERROR,
|
1112
|
+
format(
|
1113
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
1114
|
+
file: FILE,
|
1115
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE,
|
1116
|
+
exception: e
|
1117
|
+
)
|
1118
|
+
)
|
1119
|
+
nil
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
# This API method: Makes a call to our server to store the tag_values
|
1123
|
+
# 1. Validates the arguments being passed
|
1124
|
+
# 2. Send a call to our server
|
1125
|
+
# @param[String] :tag_key key name of the tag
|
1126
|
+
# @param[String] :tag_value Value of the tag
|
1127
|
+
# @param[String] :user_id ID of the user for which value should be stored
|
1128
|
+
# @return true if call is made successfully, else false
|
1129
|
+
|
1130
|
+
def push(tag_key, tag_value, user_id)
|
1131
|
+
unless @is_instance_valid
|
1132
|
+
@logger.log(
|
1133
|
+
LogLevelEnum::ERROR,
|
1134
|
+
format(
|
1135
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
1136
|
+
file: FILE,
|
1137
|
+
api_name: ApiMethods.PUSH
|
1138
|
+
)
|
1139
|
+
)
|
1140
|
+
return
|
1141
|
+
end
|
332
1142
|
|
333
|
-
|
1143
|
+
unless valid_string?(tag_key) && valid_string?(tag_value) && valid_string?(user_id)
|
1144
|
+
@logger.log(
|
1145
|
+
LogLevelEnum::ERROR,
|
1146
|
+
format(
|
1147
|
+
LogMessageEnum::ErrorMessages::PUSH_API_INVALID_PARAMS,
|
1148
|
+
file: FILE,
|
1149
|
+
api_name: ApiMethods::PUSH
|
1150
|
+
)
|
1151
|
+
)
|
1152
|
+
return false
|
1153
|
+
end
|
334
1154
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
1155
|
+
if tag_key.length > PushApi::TAG_KEY_LENGTH
|
1156
|
+
@logger.log(
|
1157
|
+
LogLevelEnum::ERROR,
|
1158
|
+
format(
|
1159
|
+
LogMessageEnum::ErrorMessages::TAG_KEY_LENGTH_EXCEEDED,
|
1160
|
+
file: FILE,
|
1161
|
+
user_id: user_id,
|
1162
|
+
tag_key: tag_key,
|
1163
|
+
api_name: ApiMethods::PUSH
|
1164
|
+
)
|
1165
|
+
)
|
1166
|
+
return false
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
if tag_value.length > PushApi::TAG_VALUE_LENGTH
|
1170
|
+
@logger.log(
|
1171
|
+
LogLevelEnum::ERROR,
|
1172
|
+
format(
|
1173
|
+
LogMessageEnum::ErrorMessages::TAG_VALUE_LENGTH_EXCEEDED,
|
1174
|
+
file: FILE,
|
1175
|
+
user_id: user_id,
|
1176
|
+
tag_value: tag_value,
|
1177
|
+
api_name: ApiMethods::PUSH
|
1178
|
+
)
|
342
1179
|
)
|
1180
|
+
return false
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
if defined?(@batch_events)
|
1184
|
+
impression = get_batch_event_url_params(@settings_file, tag_key, tag_value, user_id)
|
1185
|
+
@batch_events_queue.enqueue(impression)
|
1186
|
+
else
|
1187
|
+
impression = get_url_params(@settings_file, tag_key, tag_value, user_id, @sdk_key)
|
343
1188
|
@event_dispatcher.dispatch(impression)
|
344
|
-
|
1189
|
+
|
1190
|
+
@logger.log(
|
1191
|
+
LogLevelEnum::INFO,
|
1192
|
+
format(
|
1193
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_PUSH_API,
|
1194
|
+
file: FILE,
|
1195
|
+
sdk_key: @sdk_key,
|
1196
|
+
u: impression['u'],
|
1197
|
+
account_id: impression['account_id'],
|
1198
|
+
tags: impression['tags']
|
1199
|
+
)
|
1200
|
+
)
|
345
1201
|
end
|
1202
|
+
true
|
1203
|
+
rescue StandardError => e
|
1204
|
+
@logger.log(
|
1205
|
+
LogLevelEnum::ERROR,
|
1206
|
+
format(
|
1207
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
1208
|
+
file: FILE,
|
1209
|
+
api_name: ApiMethods::PUSH,
|
1210
|
+
exception: e
|
1211
|
+
)
|
1212
|
+
)
|
346
1213
|
false
|
347
1214
|
end
|
1215
|
+
|
1216
|
+
def get_should_track_returning_user(options)
|
1217
|
+
if !options.key?(:should_track_returning_user)
|
1218
|
+
options[:should_track_returning_user] = @should_track_returning_user
|
1219
|
+
elsif ![true, false].include?(options[:should_track_returning_user])
|
1220
|
+
@logger.log(
|
1221
|
+
LogLevelEnum::ERROR,
|
1222
|
+
format(
|
1223
|
+
LogMessageEnum::ErrorMessages::INVALID_TRACK_RETURNING_USER_VALUE,
|
1224
|
+
file: FILE
|
1225
|
+
)
|
1226
|
+
)
|
1227
|
+
end
|
1228
|
+
options[:should_track_returning_user]
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
def is_eligible_to_send_impression(should_track_returning_user = false)
|
1232
|
+
!@user_storage || !@variation_decider.has_stored_variation || should_track_returning_user
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
def flush_events
|
1236
|
+
unless @is_instance_valid
|
1237
|
+
@logger.log(
|
1238
|
+
LogLevelEnum::ERROR,
|
1239
|
+
format(
|
1240
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
1241
|
+
file: FILE,
|
1242
|
+
api_name: ApiMethods::FLUSH_EVENTS
|
1243
|
+
)
|
1244
|
+
)
|
1245
|
+
return
|
1246
|
+
end
|
1247
|
+
result = @batch_events_queue.flush(manual: true)
|
1248
|
+
@batch_events_queue.kill_thread
|
1249
|
+
result
|
1250
|
+
rescue StandardError => e
|
1251
|
+
@logger.log(
|
1252
|
+
LogLevelEnum::ERROR,
|
1253
|
+
format(
|
1254
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
1255
|
+
file: FILE,
|
1256
|
+
api_name: ApiMethods::FLUSH_EVENTS,
|
1257
|
+
exception: e
|
1258
|
+
)
|
1259
|
+
)
|
1260
|
+
false
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
def get_goal_type_to_track(options)
|
1264
|
+
goal_type_to_track = nil
|
1265
|
+
if !options.key?(:goal_type_to_track)
|
1266
|
+
if @goal_type_to_track
|
1267
|
+
goal_type_to_track = @goal_type_to_track
|
1268
|
+
else
|
1269
|
+
goal_type_to_track = GOAL_TYPES['ALL']
|
1270
|
+
end
|
1271
|
+
elsif GOAL_TYPES.key? options[:goal_type_to_track]
|
1272
|
+
goal_type_to_track = options[:goal_type_to_track]
|
1273
|
+
else
|
1274
|
+
@logger.log(
|
1275
|
+
LogLevelEnum::ERROR,
|
1276
|
+
format(
|
1277
|
+
LogMessageEnum::ErrorMessages::INVALID_GOAL_TYPE,
|
1278
|
+
file: FILE
|
1279
|
+
)
|
1280
|
+
)
|
1281
|
+
end
|
1282
|
+
goal_type_to_track
|
1283
|
+
end
|
348
1284
|
end
|