vwo-sdk 1.36.0 → 1.37.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/vwo/constants.rb +2 -2
- data/lib/vwo/core/bucketer.rb +18 -26
- data/lib/vwo/core/variation_decider.rb +216 -220
- data/lib/vwo/enums.rb +16 -19
- data/lib/vwo/logger.rb +2 -3
- data/lib/vwo/schemas/settings_file.rb +6 -6
- data/lib/vwo/services/batch_events_dispatcher.rb +19 -21
- data/lib/vwo/services/batch_events_queue.rb +27 -43
- data/lib/vwo/services/event_dispatcher.rb +31 -21
- data/lib/vwo/services/hooks_manager.rb +8 -12
- data/lib/vwo/services/segment_evaluator.rb +7 -6
- data/lib/vwo/services/settings_file_manager.rb +5 -5
- data/lib/vwo/services/settings_file_processor.rb +1 -1
- data/lib/vwo/services/usage_stats.rb +5 -4
- data/lib/vwo/utils/campaign.rb +37 -39
- data/lib/vwo/utils/custom_dimensions.rb +2 -2
- data/lib/vwo/utils/data_location_manager.rb +2 -9
- data/lib/vwo/utils/feature.rb +2 -2
- data/lib/vwo/utils/impression.rb +29 -37
- data/lib/vwo/utils/log_message.rb +23 -30
- data/lib/vwo/utils/request.rb +7 -9
- data/lib/vwo/utils/utility.rb +44 -34
- data/lib/vwo/utils/validations.rb +72 -5
- data/lib/vwo.rb +197 -344
- metadata +8 -8
data/lib/vwo.rb
CHANGED
@@ -36,6 +36,7 @@ require_relative 'vwo/services/usage_stats'
|
|
36
36
|
class VWO
|
37
37
|
attr_accessor :is_instance_valid, :logging, :settings_file_manager, :variation_decider
|
38
38
|
attr_reader :usage_stats
|
39
|
+
|
39
40
|
include Enums
|
40
41
|
include Utils::Validations
|
41
42
|
include Utils::Feature
|
@@ -128,34 +129,21 @@ class VWO
|
|
128
129
|
@is_instance_valid = true
|
129
130
|
@config = VWO::Services::SettingsFileProcessor.new(get_settings)
|
130
131
|
|
131
|
-
#Process the settings file
|
132
|
+
# Process the settings file
|
132
133
|
@config.process_settings_file
|
133
134
|
@settings_file = @config.get_settings_file
|
134
|
-
DataLocationManager.get_instance
|
135
|
+
DataLocationManager.get_instance.set_settings(@settings_file)
|
135
136
|
|
136
137
|
@usage_stats = VWO::Services::UsageStats.new(usage_stats, @is_development_mode)
|
137
138
|
|
138
139
|
if options.key?(:batch_events)
|
139
140
|
if options[:batch_events].is_a?(Hash)
|
140
|
-
unless
|
141
|
+
unless valid_batch_event_settings(options[:batch_events], ApiMethods::LAUNCH)
|
141
142
|
@is_instance_valid = false
|
142
143
|
return
|
143
144
|
end
|
144
145
|
@batch_event_dispatcher = VWO::Services::BatchEventsDispatcher.new(@is_development_mode)
|
145
|
-
|
146
|
-
@batch_event_dispatcher.dispatch(
|
147
|
-
{
|
148
|
-
ev: events
|
149
|
-
},
|
150
|
-
callback,
|
151
|
-
{
|
152
|
-
a: @account_id,
|
153
|
-
sd: SDK_NAME,
|
154
|
-
sv: SDK_VERSION,
|
155
|
-
env: @sdk_key
|
156
|
-
}.merge(@usage_stats.usage_stats)
|
157
|
-
)
|
158
|
-
end
|
146
|
+
|
159
147
|
@batch_events_queue = VWO::Services::BatchEventsQueue.new(
|
160
148
|
options[:batch_events].merge(
|
161
149
|
{
|
@@ -192,7 +180,22 @@ class VWO
|
|
192
180
|
@logger.log(
|
193
181
|
LogLevelEnum::INFO,
|
194
182
|
'SDK_INITIALIZED',
|
195
|
-
{'{file}' => FILE}
|
183
|
+
{ '{file}' => FILE }
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
def dispatcher(events, callback)
|
188
|
+
@batch_event_dispatcher.dispatch(
|
189
|
+
{
|
190
|
+
ev: events
|
191
|
+
},
|
192
|
+
callback,
|
193
|
+
{
|
194
|
+
a: @account_id,
|
195
|
+
sd: SDK_NAME,
|
196
|
+
sv: SDK_VERSION,
|
197
|
+
env: @sdk_key
|
198
|
+
}.merge(@usage_stats.usage_stats)
|
196
199
|
)
|
197
200
|
end
|
198
201
|
|
@@ -210,9 +213,7 @@ class VWO
|
|
210
213
|
# VWO get_settings method to get settings for a particular account_id
|
211
214
|
def get_and_update_settings_file
|
212
215
|
@logger.set_api_name(ApiMethods::GET_AND_UPDATE_SETTINGS_FILE)
|
213
|
-
if
|
214
|
-
return false
|
215
|
-
end
|
216
|
+
return false if opted_out?(ApiMethods::GET_AND_UPDATE_SETTINGS_FILE)
|
216
217
|
|
217
218
|
unless @is_instance_valid
|
218
219
|
@logger.log(
|
@@ -245,7 +246,7 @@ class VWO
|
|
245
246
|
rescue StandardError => e
|
246
247
|
@logger.log(
|
247
248
|
LogLevelEnum::ERROR,
|
248
|
-
|
249
|
+
"({file}): {api} API error: #{e.message}",
|
249
250
|
{
|
250
251
|
'{file}' => FILE,
|
251
252
|
'{api}' => ApiMethods::GET_AND_UPDATE_SETTINGS_FILE
|
@@ -273,9 +274,7 @@ class VWO
|
|
273
274
|
|
274
275
|
def activate(campaign_key, user_id, options = {})
|
275
276
|
@logger.set_api_name(ApiMethods::ACTIVATE)
|
276
|
-
if
|
277
|
-
return nil
|
278
|
-
end
|
277
|
+
return nil if opted_out?(ApiMethods::ACTIVATE)
|
279
278
|
|
280
279
|
unless @is_instance_valid
|
281
280
|
@logger.log(
|
@@ -296,7 +295,7 @@ class VWO
|
|
296
295
|
|
297
296
|
# Validate input parameters
|
298
297
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
299
|
-
|
298
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
300
299
|
@logger.log(
|
301
300
|
LogLevelEnum::ERROR,
|
302
301
|
'API_BAD_PARAMETERS',
|
@@ -339,7 +338,7 @@ class VWO
|
|
339
338
|
'{api}' => ApiMethods::ACTIVATE,
|
340
339
|
'{userId}' => user_id,
|
341
340
|
'{campaignKey}' => campaign_key,
|
342
|
-
'{campaignType}' => campaign_type
|
341
|
+
'{campaignType}' => campaign_type
|
343
342
|
}
|
344
343
|
)
|
345
344
|
return
|
@@ -358,11 +357,9 @@ class VWO
|
|
358
357
|
)
|
359
358
|
|
360
359
|
# Check if variation_name has been assigned
|
361
|
-
if variation.nil?
|
362
|
-
return
|
363
|
-
end
|
360
|
+
return if variation.nil?
|
364
361
|
|
365
|
-
if
|
362
|
+
if eligible_to_send_impression?
|
366
363
|
if defined?(@batch_events)
|
367
364
|
impression = create_bulk_event_impression(
|
368
365
|
@settings_file,
|
@@ -371,7 +368,7 @@ class VWO
|
|
371
368
|
user_id
|
372
369
|
)
|
373
370
|
@batch_events_queue.enqueue(impression)
|
374
|
-
elsif
|
371
|
+
elsif event_arch_enabled?
|
375
372
|
properties = get_events_base_properties(@settings_file, EventEnum::VWO_VARIATION_SHOWN, @usage_stats.usage_stats)
|
376
373
|
payload = get_track_user_payload_data(@settings_file, user_id, EventEnum::VWO_VARIATION_SHOWN, campaign['id'], variation['id'])
|
377
374
|
@event_dispatcher.dispatch_event_arch_post(properties, payload)
|
@@ -387,18 +384,8 @@ class VWO
|
|
387
384
|
nil, # revenue
|
388
385
|
usage_stats: @usage_stats.usage_stats
|
389
386
|
)
|
390
|
-
|
391
|
-
|
392
|
-
LogLevelEnum::INFO,
|
393
|
-
'IMPRESSION_SUCCESS',
|
394
|
-
{
|
395
|
-
'{file}' => FILE,
|
396
|
-
'{mainKeys}' => JSON.generate({'campaignId' => campaign['id'], 'variationId' => variation['id']}),
|
397
|
-
'{accountId}' => @account_id,
|
398
|
-
'{endPoint}' => EVENTS::TRACK_USER
|
399
|
-
}
|
400
|
-
)
|
401
|
-
end
|
387
|
+
main_keys = { 'campaignId' => campaign['id'], 'variationId' => variation['id'] }
|
388
|
+
@event_dispatcher.dispatch(impression, main_keys, EVENTS::TRACK_USER)
|
402
389
|
end
|
403
390
|
else
|
404
391
|
@logger.log(
|
@@ -416,7 +403,7 @@ class VWO
|
|
416
403
|
rescue StandardError => e
|
417
404
|
@logger.log(
|
418
405
|
LogLevelEnum::ERROR,
|
419
|
-
|
406
|
+
"({file}): {api} API error: #{e.message}",
|
420
407
|
{
|
421
408
|
'{file}' => FILE,
|
422
409
|
'{api}' => ApiMethods::ACTIVATE
|
@@ -444,9 +431,7 @@ class VWO
|
|
444
431
|
#
|
445
432
|
def get_variation_name(campaign_key, user_id, options = {})
|
446
433
|
@logger.set_api_name(ApiMethods::GET_VARIATION_NAME)
|
447
|
-
if
|
448
|
-
return nil
|
449
|
-
end
|
434
|
+
return nil if opted_out?(ApiMethods::GET_VARIATION_NAME)
|
450
435
|
|
451
436
|
unless @is_instance_valid
|
452
437
|
@logger.log(
|
@@ -466,7 +451,7 @@ class VWO
|
|
466
451
|
|
467
452
|
# Validate input parameters
|
468
453
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
469
|
-
|
454
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
470
455
|
@logger.log(
|
471
456
|
LogLevelEnum::ERROR,
|
472
457
|
'API_BAD_PARAMETERS',
|
@@ -506,7 +491,23 @@ class VWO
|
|
506
491
|
'{api}' => ApiMethods::GET_VARIATION_NAME,
|
507
492
|
'{userId}' => user_id,
|
508
493
|
'{campaignKey}' => campaign_key,
|
509
|
-
'{campaignType}' => campaign_type
|
494
|
+
'{campaignType}' => campaign_type
|
495
|
+
}
|
496
|
+
)
|
497
|
+
return
|
498
|
+
end
|
499
|
+
|
500
|
+
case campaign_type
|
501
|
+
when CampaignTypes::FEATURE_ROLLOUT
|
502
|
+
@logger.log(
|
503
|
+
LogLevelEnum::ERROR,
|
504
|
+
'API_NOT_APPLICABLE',
|
505
|
+
{
|
506
|
+
'{file}' => FILE,
|
507
|
+
'{api}' => ApiMethods::GET_VARIATION_NAME,
|
508
|
+
'{userId}' => user_id,
|
509
|
+
'{campaignKey}' => campaign_key,
|
510
|
+
'{campaignType}' => campaign_type
|
510
511
|
}
|
511
512
|
)
|
512
513
|
return
|
@@ -515,15 +516,13 @@ class VWO
|
|
515
516
|
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::GET_VARIATION_NAME, campaign_key, custom_variables, variation_targeting_variables)
|
516
517
|
|
517
518
|
# Check if variation_name has been assigned
|
518
|
-
unless valid_value?(variation)
|
519
|
-
return
|
520
|
-
end
|
519
|
+
return unless valid_value?(variation)
|
521
520
|
|
522
521
|
variation['name']
|
523
522
|
rescue StandardError => e
|
524
523
|
@logger.log(
|
525
524
|
LogLevelEnum::ERROR,
|
526
|
-
|
525
|
+
"({file}): {api} API error: #{e.message}",
|
527
526
|
{
|
528
527
|
'{file}' => FILE,
|
529
528
|
'{api}' => ApiMethods::GET_VARIATION_NAME
|
@@ -543,15 +542,12 @@ class VWO
|
|
543
542
|
# @param[String] :campaign_key Unique campaign key
|
544
543
|
# @param[String] :user_id ID assigned to a user
|
545
544
|
# @param[String] :goal_identifier Unique campaign's goal identifier
|
546
|
-
# @param[Hash] :options
|
547
|
-
# @param[Numeric|String] :revenue_value It is the revenue generated on triggering the goal
|
545
|
+
# @param[Hash] :options Contains revenue value and custom variables
|
548
546
|
#
|
549
547
|
|
550
548
|
def track(campaign_key, user_id, goal_identifier, options = {})
|
551
549
|
@logger.set_api_name(ApiMethods::TRACK)
|
552
|
-
if
|
553
|
-
return false
|
554
|
-
end
|
550
|
+
return false if opted_out?(ApiMethods::TRACK)
|
555
551
|
|
556
552
|
unless @is_instance_valid
|
557
553
|
@logger.log(
|
@@ -572,168 +568,59 @@ class VWO
|
|
572
568
|
goal_type_to_track = get_goal_type_to_track(options)
|
573
569
|
|
574
570
|
# Check for valid args
|
575
|
-
|
576
|
-
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && (GOAL_TYPES.key? (goal_type_to_track))
|
577
|
-
# log invalid params
|
578
|
-
@logger.log(
|
579
|
-
LogLevelEnum::ERROR,
|
580
|
-
'API_BAD_PARAMETERS',
|
581
|
-
{
|
582
|
-
'{file}' => FILE,
|
583
|
-
'{api}' => ApiMethods::TRACK
|
584
|
-
}
|
585
|
-
)
|
586
|
-
return false
|
587
|
-
end
|
571
|
+
return false unless valid_track_api_params?(user_id, campaign_key, custom_variables, variation_targeting_variables, goal_type_to_track, goal_identifier)
|
588
572
|
|
589
573
|
# Get campaigns settings
|
590
574
|
campaigns = get_campaigns(@settings_file, campaign_key, goal_identifier, goal_type_to_track)
|
591
575
|
|
592
576
|
# Validate campaign
|
593
|
-
if campaigns.nil?
|
594
|
-
return nil
|
595
|
-
end
|
577
|
+
return nil if campaigns.nil?
|
596
578
|
|
597
579
|
metric_map = {}
|
598
580
|
revenue_props = []
|
599
581
|
result = {}
|
600
|
-
batch_event_data = {
|
582
|
+
batch_event_data = { 'ev' => [] }
|
601
583
|
campaigns.each do |campaign|
|
602
584
|
begin
|
603
585
|
campaign_type = campaign['type']
|
586
|
+
result[campaign['key']] = false
|
604
587
|
|
605
|
-
|
606
|
-
@logger.log(
|
607
|
-
LogLevelEnum::ERROR,
|
608
|
-
'API_NOT_APPLICABLE',
|
609
|
-
{
|
610
|
-
'{file}' => FILE,
|
611
|
-
'{api}' => ApiMethods::TRACK,
|
612
|
-
'{userId}' => user_id,
|
613
|
-
'{campaignKey}' => campaign_key,
|
614
|
-
'{campaignType}' => campaign_type,
|
615
|
-
}
|
616
|
-
)
|
617
|
-
result[campaign['key']] = false
|
618
|
-
next
|
619
|
-
end
|
588
|
+
next unless valid_campaign_for_track_api?(user_id, campaign_key, campaign_type)
|
620
589
|
|
621
590
|
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::TRACK, campaign['key'], custom_variables, variation_targeting_variables, goal_identifier)
|
622
591
|
|
623
592
|
if variation
|
624
593
|
goal = get_campaign_goal(campaign, goal_identifier)
|
625
|
-
|
626
|
-
@logger.log(
|
627
|
-
LogLevelEnum::ERROR,
|
628
|
-
'TRACK_API_GOAL_NOT_FOUND',
|
629
|
-
{
|
630
|
-
'{file}' => FILE,
|
631
|
-
'{goalIdentifier}' => goal_identifier,
|
632
|
-
'{userId}' => user_id,
|
633
|
-
'{campaignKey}' => campaign['key']
|
634
|
-
}
|
635
|
-
)
|
636
|
-
result[campaign['key']] = false
|
637
|
-
next
|
638
|
-
elsif goal['type'] == GoalTypes::REVENUE && !valid_value?(revenue_value)
|
639
|
-
@logger.log(
|
640
|
-
LogLevelEnum::ERROR,
|
641
|
-
'TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL',
|
642
|
-
{
|
643
|
-
'{file}' => FILE,
|
644
|
-
'{userId}' => user_id,
|
645
|
-
'{goalIdentifier}' => goal_identifier,
|
646
|
-
'{campaignKey}' => campaign['key']
|
647
|
-
}
|
648
|
-
)
|
649
|
-
result[campaign['key']] = false
|
650
|
-
next
|
651
|
-
elsif goal['type'] == GoalTypes::CUSTOM
|
652
|
-
revenue_value = nil
|
653
|
-
end
|
594
|
+
next unless valid_goal?(goal, campaign, user_id, goal_identifier, revenue_value)
|
654
595
|
|
655
|
-
if
|
656
|
-
|
657
|
-
else
|
658
|
-
variation['goal_identifier'] = ''
|
659
|
-
identifiers = []
|
660
|
-
end
|
596
|
+
revenue_value = nil if goal['type'] == GoalTypes::CUSTOM
|
597
|
+
identifiers = get_variation_identifiers(variation)
|
661
598
|
|
662
|
-
if
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
# set variation at user storage
|
667
|
-
else
|
668
|
-
@logger.log(
|
669
|
-
LogLevelEnum::INFO,
|
670
|
-
'CAMPAIGN_GOAL_ALREADY_TRACKED',
|
671
|
-
{
|
672
|
-
'{file}' => FILE,
|
673
|
-
'{userId}' => user_id,
|
674
|
-
'{campaignKey}' => campaign['key'],
|
675
|
-
'{goalIdentifier}' => goal_identifier
|
676
|
-
}
|
677
|
-
)
|
678
|
-
result[campaign['key']] = false
|
679
|
-
next
|
680
|
-
end
|
599
|
+
next if campaign_goal_already_tracked?(user_id, campaign, identifiers, goal_identifier)
|
600
|
+
|
601
|
+
@variation_decider.update_goal_identifier(user_id, campaign, variation, goal_identifier)
|
602
|
+
# set variation at user storage
|
681
603
|
|
682
604
|
if defined?(@batch_events)
|
683
|
-
impression = create_bulk_event_impression(
|
684
|
-
@settings_file,
|
685
|
-
campaign['id'],
|
686
|
-
variation['id'],
|
687
|
-
user_id,
|
688
|
-
goal['id'],
|
689
|
-
revenue_value
|
690
|
-
)
|
605
|
+
impression = create_bulk_event_impression(@settings_file, campaign['id'], variation['id'], user_id, goal['id'], revenue_value)
|
691
606
|
@batch_events_queue.enqueue(impression)
|
692
|
-
elsif
|
607
|
+
elsif event_arch_enabled?
|
693
608
|
metric_map[campaign['id']] = goal['id']
|
694
|
-
if goal['type'] == GoalTypes::REVENUE && !(revenue_props.include? goal['revenueProp'])
|
695
|
-
revenue_props << goal['revenueProp']
|
696
|
-
end
|
609
|
+
revenue_props << goal['revenueProp'] if goal['type'] == GoalTypes::REVENUE && !(revenue_props.include? goal['revenueProp'])
|
697
610
|
elsif campaigns.count == 1
|
698
|
-
impression = create_impression(
|
699
|
-
|
700
|
-
|
701
|
-
variation['id'],
|
702
|
-
user_id,
|
703
|
-
@sdk_key,
|
704
|
-
goal['id'],
|
705
|
-
revenue_value
|
706
|
-
)
|
707
|
-
if @event_dispatcher.dispatch(impression)
|
708
|
-
@logger.log(
|
709
|
-
LogLevelEnum::INFO,
|
710
|
-
'IMPRESSION_SUCCESS',
|
711
|
-
{
|
712
|
-
'{file}' => FILE,
|
713
|
-
'{mainKeys}' => JSON.generate({'campaignId' => campaign['id'], 'variationId' => variation['id'], 'goalId' => goal['id']}),
|
714
|
-
'{accountId}' => @account_id,
|
715
|
-
'{endPoint}' => EVENTS::TRACK_GOAL
|
716
|
-
}
|
717
|
-
)
|
718
|
-
end
|
611
|
+
impression = create_impression(@settings_file, campaign['id'], variation['id'], user_id, @sdk_key, goal['id'], revenue_value)
|
612
|
+
main_keys = { 'campaignId' => campaign['id'], 'variationId' => variation['id'], 'goalId' => goal['id'] }
|
613
|
+
@event_dispatcher.dispatch(impression, main_keys, EVENTS::TRACK_GOAL)
|
719
614
|
else
|
720
|
-
batch_event_data[
|
721
|
-
@settings_file,
|
722
|
-
campaign['id'],
|
723
|
-
variation['id'],
|
724
|
-
user_id,
|
725
|
-
goal['id'],
|
726
|
-
revenue_value
|
727
|
-
)
|
615
|
+
batch_event_data['ev'] << create_bulk_event_impression(@settings_file, campaign['id'], variation['id'], user_id, goal['id'], revenue_value)
|
728
616
|
end
|
729
617
|
result[campaign['key']] = true
|
730
618
|
next
|
731
619
|
end
|
732
|
-
result[campaign['key']] = false
|
733
620
|
rescue StandardError => e
|
734
621
|
@logger.log(
|
735
622
|
LogLevelEnum::ERROR,
|
736
|
-
|
623
|
+
"({file}): {api} API error: #{e.message}",
|
737
624
|
{
|
738
625
|
'{file}' => FILE,
|
739
626
|
'{api}' => ApiMethods::TRACK
|
@@ -742,26 +629,23 @@ class VWO
|
|
742
629
|
end
|
743
630
|
end
|
744
631
|
|
745
|
-
|
746
|
-
if is_event_arch_enabled
|
632
|
+
if event_arch_enabled?
|
747
633
|
properties = get_events_base_properties(@settings_file, goal_identifier)
|
748
634
|
payload = get_track_goal_payload_data(@settings_file, user_id, goal_identifier, revenue_value, metric_map, revenue_props)
|
749
635
|
@event_dispatcher.dispatch_event_arch_post(properties, payload)
|
750
|
-
elsif batch_event_data[
|
636
|
+
elsif batch_event_data['ev'].count != 0
|
751
637
|
paramters = get_batch_event_query_params(@settings_file['accountId'], @sdk_key, @usage_stats.usage_stats)
|
752
638
|
batch_events_dispatcher = VWO::Services::BatchEventsDispatcher.new(@is_development_mode)
|
753
|
-
|
639
|
+
return nil unless batch_events_dispatcher.dispatch(batch_event_data, nil, paramters)
|
754
640
|
end
|
755
641
|
|
756
|
-
if result.length
|
757
|
-
return nil
|
758
|
-
end
|
642
|
+
return nil if result.length == 0
|
759
643
|
|
760
644
|
result
|
761
645
|
rescue StandardError => e
|
762
646
|
@logger.log(
|
763
647
|
LogLevelEnum::ERROR,
|
764
|
-
|
648
|
+
"({file}): {api} API error: #{e.message}",
|
765
649
|
{
|
766
650
|
'{file}' => FILE,
|
767
651
|
'{api}' => ApiMethods::TRACK
|
@@ -769,7 +653,6 @@ class VWO
|
|
769
653
|
)
|
770
654
|
false
|
771
655
|
end
|
772
|
-
|
773
656
|
# This API method: Identifies whether the user becomes a part of feature rollout/test or not.
|
774
657
|
# 1. Validates the arguments being passed
|
775
658
|
# 2. Checks if user is eligible to get bucketed into the feature test/rollout,
|
@@ -785,9 +668,7 @@ class VWO
|
|
785
668
|
|
786
669
|
def feature_enabled?(campaign_key, user_id, options = {})
|
787
670
|
@logger.set_api_name(ApiMethods::IS_FEATURE_ENABLED)
|
788
|
-
if
|
789
|
-
return false
|
790
|
-
end
|
671
|
+
return false if opted_out?(ApiMethods::IS_FEATURE_ENABLED)
|
791
672
|
|
792
673
|
unless @is_instance_valid
|
793
674
|
@logger.log(
|
@@ -808,7 +689,7 @@ class VWO
|
|
808
689
|
|
809
690
|
# Validate input parameters
|
810
691
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
811
|
-
|
692
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
812
693
|
@logger.log(
|
813
694
|
LogLevelEnum::ERROR,
|
814
695
|
'API_BAD_PARAMETERS',
|
@@ -850,7 +731,7 @@ class VWO
|
|
850
731
|
'{api}' => ApiMethods::IS_FEATURE_ENABLED,
|
851
732
|
'{userId}' => user_id,
|
852
733
|
'{campaignKey}' => campaign_key,
|
853
|
-
'{campaignType}' => campaign_type
|
734
|
+
'{campaignType}' => campaign_type
|
854
735
|
}
|
855
736
|
)
|
856
737
|
return false
|
@@ -864,7 +745,7 @@ class VWO
|
|
864
745
|
|
865
746
|
# if campaign type is feature_test Send track call to server
|
866
747
|
|
867
|
-
if
|
748
|
+
if eligible_to_send_impression?
|
868
749
|
if defined?(@batch_events)
|
869
750
|
impression = create_bulk_event_impression(
|
870
751
|
@settings_file,
|
@@ -873,7 +754,7 @@ class VWO
|
|
873
754
|
user_id
|
874
755
|
)
|
875
756
|
@batch_events_queue.enqueue(impression)
|
876
|
-
elsif
|
757
|
+
elsif event_arch_enabled?
|
877
758
|
properties = get_events_base_properties(@settings_file, EventEnum::VWO_VARIATION_SHOWN, @usage_stats.usage_stats)
|
878
759
|
payload = get_track_user_payload_data(@settings_file, user_id, EventEnum::VWO_VARIATION_SHOWN, campaign['id'], variation['id'])
|
879
760
|
@event_dispatcher.dispatch_event_arch_post(properties, payload)
|
@@ -889,17 +770,8 @@ class VWO
|
|
889
770
|
usage_stats: @usage_stats.usage_stats
|
890
771
|
)
|
891
772
|
|
892
|
-
|
893
|
-
@
|
894
|
-
LogLevelEnum::INFO,
|
895
|
-
'IMPRESSION_SUCCESS',
|
896
|
-
{
|
897
|
-
'{file}' => FILE,
|
898
|
-
'{mainKeys}' => JSON.generate({'campaignId' => impression[:experiment_id]}),
|
899
|
-
'{accountId}' => @account_id,
|
900
|
-
'{endPoint}' => EVENTS::TRACK_USER
|
901
|
-
}
|
902
|
-
)
|
773
|
+
main_keys = { 'campaignId' => impression[:experiment_id] }
|
774
|
+
@event_dispatcher.dispatch(impression, main_keys, EVENTS::TRACK_USER)
|
903
775
|
end
|
904
776
|
|
905
777
|
else
|
@@ -914,11 +786,11 @@ class VWO
|
|
914
786
|
}
|
915
787
|
)
|
916
788
|
end
|
917
|
-
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
789
|
+
result = if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
790
|
+
true
|
791
|
+
else
|
792
|
+
variation['isFeatureEnabled']
|
793
|
+
end
|
922
794
|
|
923
795
|
if result
|
924
796
|
@logger.log(
|
@@ -948,7 +820,7 @@ class VWO
|
|
948
820
|
rescue StandardError => e
|
949
821
|
@logger.log(
|
950
822
|
LogLevelEnum::ERROR,
|
951
|
-
|
823
|
+
"({file}): {api} API error: #{e.message}",
|
952
824
|
{
|
953
825
|
'{file}' => FILE,
|
954
826
|
'{api}' => ApiMethods::IS_FEATURE_ENABLED
|
@@ -978,9 +850,7 @@ class VWO
|
|
978
850
|
|
979
851
|
def get_feature_variable_value(campaign_key, variable_key, user_id, options = {})
|
980
852
|
@logger.set_api_name(ApiMethods::GET_FEATURE_VARIABLE_VALUE)
|
981
|
-
if
|
982
|
-
return nil
|
983
|
-
end
|
853
|
+
return nil if opted_out?(ApiMethods::GET_FEATURE_VARIABLE_VALUE)
|
984
854
|
|
985
855
|
unless @is_instance_valid
|
986
856
|
@logger.log(
|
@@ -1000,7 +870,7 @@ class VWO
|
|
1000
870
|
variation_targeting_variables = options[:variation_targeting_variables]
|
1001
871
|
|
1002
872
|
unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
|
1003
|
-
|
873
|
+
(custom_variables.nil? || valid_hash?(custom_variables)) && (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
1004
874
|
@logger.log(
|
1005
875
|
LogLevelEnum::ERROR,
|
1006
876
|
'API_BAD_PARAMETERS',
|
@@ -1041,7 +911,7 @@ class VWO
|
|
1041
911
|
'{api}' => ApiMethods::GET_FEATURE_VARIABLE_VALUE,
|
1042
912
|
'{userId}' => user_id,
|
1043
913
|
'{campaignKey}' => campaign_key,
|
1044
|
-
'{campaignType}' => campaign_type
|
914
|
+
'{campaignType}' => campaign_type
|
1045
915
|
}
|
1046
916
|
)
|
1047
917
|
return
|
@@ -1052,32 +922,33 @@ class VWO
|
|
1052
922
|
# Check if variation has been assigned to user
|
1053
923
|
return unless variation
|
1054
924
|
|
1055
|
-
|
925
|
+
case campaign_type
|
926
|
+
when CampaignTypes::FEATURE_ROLLOUT
|
1056
927
|
variables = campaign['variables']
|
1057
|
-
|
928
|
+
when CampaignTypes::FEATURE_TEST
|
1058
929
|
if !variation['isFeatureEnabled']
|
1059
930
|
@logger.log(
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
931
|
+
LogLevelEnum::INFO,
|
932
|
+
'FEATURE_STATUS',
|
933
|
+
{
|
934
|
+
'{file}' => FILE,
|
935
|
+
'{userId}' => user_id,
|
936
|
+
'{campaignKey}' => campaign_key,
|
937
|
+
'{status}' => 'disabled'
|
938
|
+
}
|
939
|
+
)
|
1069
940
|
variation = get_control_variation(campaign)
|
1070
941
|
else
|
1071
942
|
@logger.log(
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
943
|
+
LogLevelEnum::INFO,
|
944
|
+
'FEATURE_STATUS',
|
945
|
+
{
|
946
|
+
'{file}' => FILE,
|
947
|
+
'{userId}' => user_id,
|
948
|
+
'{campaignKey}' => campaign_key,
|
949
|
+
'{status}' => 'enabled'
|
950
|
+
}
|
951
|
+
)
|
1081
952
|
end
|
1082
953
|
variables = variation['variables']
|
1083
954
|
end
|
@@ -1105,14 +976,14 @@ class VWO
|
|
1105
976
|
'{variableKey}' => variable_key,
|
1106
977
|
'{variableValue}' => variable['value'],
|
1107
978
|
'{campaignKey}' => campaign_key,
|
1108
|
-
'{userId}' => user_id
|
979
|
+
'{userId}' => user_id
|
1109
980
|
}
|
1110
981
|
)
|
1111
982
|
get_type_casted_feature_value(variable['value'], variable['type'])
|
1112
983
|
rescue StandardError => e
|
1113
984
|
@logger.log(
|
1114
985
|
LogLevelEnum::ERROR,
|
1115
|
-
|
986
|
+
"({file}): {api} API error: #{e.message}",
|
1116
987
|
{
|
1117
988
|
'{file}' => FILE,
|
1118
989
|
'{api}' => ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
@@ -1131,9 +1002,7 @@ class VWO
|
|
1131
1002
|
|
1132
1003
|
def push(tag_key, tag_value, user_id = nil)
|
1133
1004
|
@logger.set_api_name(ApiMethods::PUSH)
|
1134
|
-
if
|
1135
|
-
return {}
|
1136
|
-
end
|
1005
|
+
return {} if opted_out?(ApiMethods::PUSH)
|
1137
1006
|
|
1138
1007
|
unless @is_instance_valid
|
1139
1008
|
@logger.log(
|
@@ -1169,42 +1038,42 @@ class VWO
|
|
1169
1038
|
end
|
1170
1039
|
|
1171
1040
|
result = {}
|
1172
|
-
custom_dimension_map.each do |
|
1173
|
-
if !
|
1174
|
-
custom_dimension_map.delete(
|
1175
|
-
result[
|
1041
|
+
custom_dimension_map.each do |tagkey, tagvalue|
|
1042
|
+
if !tagkey.is_a?(Symbol) || !tagvalue.is_a?(String)
|
1043
|
+
custom_dimension_map.delete(tagkey)
|
1044
|
+
result[tagkey] = false
|
1176
1045
|
next
|
1177
1046
|
end
|
1178
1047
|
|
1179
|
-
if
|
1048
|
+
if tagkey.length > PushApi::TAG_KEY_LENGTH || tagkey.length == 0
|
1180
1049
|
@logger.log(
|
1181
1050
|
LogLevelEnum::ERROR,
|
1182
1051
|
'TAG_KEY_LENGTH_EXCEEDED',
|
1183
1052
|
{
|
1184
1053
|
'{file}' => FILE,
|
1185
1054
|
'{userId}' => user_id,
|
1186
|
-
'{tagKey}' =>
|
1055
|
+
'{tagKey}' => tagkey
|
1187
1056
|
}
|
1188
1057
|
)
|
1189
|
-
custom_dimension_map.delete(
|
1190
|
-
result[
|
1058
|
+
custom_dimension_map.delete(tagkey)
|
1059
|
+
result[tagkey] = false
|
1191
1060
|
next
|
1192
1061
|
end
|
1193
1062
|
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
}
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1063
|
+
next unless tagvalue.length > PushApi::TAG_VALUE_LENGTH || tagvalue.length == 0
|
1064
|
+
|
1065
|
+
@logger.log(
|
1066
|
+
LogLevelEnum::ERROR,
|
1067
|
+
'TAG_VALUE_LENGTH_EXCEEDED',
|
1068
|
+
{
|
1069
|
+
'{file}' => FILE,
|
1070
|
+
'{userId}' => user_id,
|
1071
|
+
'{tagKey}' => tagkey,
|
1072
|
+
'{tagValue}' => tagvalue
|
1073
|
+
}
|
1074
|
+
)
|
1075
|
+
custom_dimension_map.delete(tagkey)
|
1076
|
+
result[tagkey] = false
|
1208
1077
|
end
|
1209
1078
|
|
1210
1079
|
if custom_dimension_map.count == 0
|
@@ -1220,62 +1089,51 @@ class VWO
|
|
1220
1089
|
end
|
1221
1090
|
|
1222
1091
|
if defined?(@batch_events)
|
1223
|
-
custom_dimension_map.each do |
|
1224
|
-
impression = get_batch_event_url_params(@settings_file,
|
1092
|
+
custom_dimension_map.each do |tagkey, tagvalue|
|
1093
|
+
impression = get_batch_event_url_params(@settings_file, tagkey, tagvalue, user_id)
|
1225
1094
|
@batch_events_queue.enqueue(impression)
|
1226
1095
|
end
|
1227
1096
|
resp = true
|
1228
|
-
elsif
|
1097
|
+
elsif event_arch_enabled?
|
1229
1098
|
properties = get_events_base_properties(@settings_file, EventEnum::VWO_SYNC_VISITOR_PROP)
|
1230
1099
|
payload = get_push_payload_data(@settings_file, user_id, EventEnum::VWO_SYNC_VISITOR_PROP, custom_dimension_map)
|
1231
1100
|
resp = @event_dispatcher.dispatch_event_arch_post(properties, payload)
|
1232
1101
|
elsif custom_dimension_map.count == 1
|
1233
|
-
custom_dimension_map.each do |
|
1234
|
-
impression = get_url_params(@settings_file,
|
1235
|
-
|
1236
|
-
@
|
1237
|
-
LogLevelEnum::INFO,
|
1238
|
-
'IMPRESSION_SUCCESS',
|
1239
|
-
{
|
1240
|
-
'{file}' => FILE,
|
1241
|
-
'{endPoint}' => ApiMethods::PUSH,
|
1242
|
-
'{accountId}' => @settings_file['accountId'],
|
1243
|
-
'{mainKeys}' => JSON.generate({'tags' => impression['tags']}),
|
1244
|
-
}
|
1245
|
-
)
|
1102
|
+
custom_dimension_map.each do |tagkey, tagvalue|
|
1103
|
+
impression = get_url_params(@settings_file, tagkey, tagvalue, user_id, @sdk_key)
|
1104
|
+
main_keys = { 'tags' => impression['tags'] }
|
1105
|
+
result[tagkey] = @event_dispatcher.dispatch(impression, main_keys, EVENTS::PUSH)
|
1246
1106
|
end
|
1247
1107
|
resp = true
|
1248
1108
|
else
|
1249
|
-
batch_event_data = {
|
1250
|
-
custom_dimension_map.each do |
|
1251
|
-
batch_event_data[
|
1109
|
+
batch_event_data = { 'ev' => [] }
|
1110
|
+
custom_dimension_map.each do |tagkey, tagvalue|
|
1111
|
+
batch_event_data['ev'] << get_batch_event_url_params(@settings_file, tagkey, tagvalue, user_id)
|
1252
1112
|
end
|
1253
1113
|
paramters = get_batch_event_query_params(@settings_file['accountId'], @sdk_key, @usage_stats.usage_stats)
|
1254
1114
|
batch_events_dispatcher = VWO::Services::BatchEventsDispatcher.new(@is_development_mode)
|
1255
1115
|
resp = batch_events_dispatcher.dispatch(batch_event_data, nil, paramters)
|
1256
1116
|
end
|
1257
1117
|
|
1258
|
-
|
1118
|
+
prepare_push_response(custom_dimension_map, resp, result)
|
1259
1119
|
rescue StandardError => e
|
1260
1120
|
@logger.log(
|
1261
1121
|
LogLevelEnum::ERROR,
|
1262
|
-
|
1263
|
-
{'{file}' => FILE}
|
1122
|
+
"({file}): push API error: #{e.message}",
|
1123
|
+
{ '{file}' => FILE }
|
1264
1124
|
)
|
1265
1125
|
false
|
1266
1126
|
end
|
1267
1127
|
|
1268
|
-
def
|
1128
|
+
def eligible_to_send_impression?
|
1269
1129
|
!@user_storage || !@variation_decider.has_stored_variation
|
1270
1130
|
end
|
1271
1131
|
|
1272
1132
|
# Manually flush impression events to VWO which are queued in batch queue as per batchEvents config
|
1273
|
-
# @return[bool]
|
1133
|
+
# @return[bool]
|
1274
1134
|
def flush_events
|
1275
1135
|
@logger.set_api_name(ApiMethods::FLUSH_EVENTS)
|
1276
|
-
if
|
1277
|
-
return false
|
1278
|
-
end
|
1136
|
+
return false if opted_out?(ApiMethods::FLUSH_EVENTS)
|
1279
1137
|
|
1280
1138
|
unless @is_instance_valid
|
1281
1139
|
@logger.log(
|
@@ -1297,7 +1155,7 @@ class VWO
|
|
1297
1155
|
rescue StandardError => e
|
1298
1156
|
@logger.log(
|
1299
1157
|
LogLevelEnum::ERROR,
|
1300
|
-
|
1158
|
+
"({file}): {api} API error: #{e.message}",
|
1301
1159
|
{
|
1302
1160
|
'{file}' => FILE,
|
1303
1161
|
'{api}' => ApiMethods::FLUSH_EVENTS
|
@@ -1309,24 +1167,20 @@ class VWO
|
|
1309
1167
|
def get_goal_type_to_track(options)
|
1310
1168
|
goal_type_to_track = nil
|
1311
1169
|
if !options.key?(:goal_type_to_track)
|
1312
|
-
|
1313
|
-
goal_type_to_track = @goal_type_to_track
|
1314
|
-
else
|
1315
|
-
goal_type_to_track = GOAL_TYPES['ALL']
|
1316
|
-
end
|
1170
|
+
goal_type_to_track = @goal_type_to_track || GOAL_TYPES['ALL']
|
1317
1171
|
elsif GOAL_TYPES.key? options[:goal_type_to_track]
|
1318
1172
|
goal_type_to_track = options[:goal_type_to_track]
|
1319
1173
|
else
|
1320
1174
|
@logger.log(
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1175
|
+
LogLevelEnum::ERROR,
|
1176
|
+
'CONFIG_PARAMETER_INVALID',
|
1177
|
+
{
|
1178
|
+
'{file}' => FILE,
|
1179
|
+
'{parameter}' => 'goal_type_to_track',
|
1180
|
+
'{type}' => 'string(REVENUE, CUSTOM, ALL)',
|
1181
|
+
'{api}' => 'init'
|
1182
|
+
}
|
1183
|
+
)
|
1330
1184
|
end
|
1331
1185
|
goal_type_to_track
|
1332
1186
|
end
|
@@ -1336,38 +1190,37 @@ class VWO
|
|
1336
1190
|
# return[bool]
|
1337
1191
|
#
|
1338
1192
|
def set_opt_out
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1193
|
+
@logger.set_api_name(ApiMethods::OPT_OUT)
|
1194
|
+
@logger.log(
|
1195
|
+
LogLevelEnum::INFO,
|
1196
|
+
'OPT_OUT_API_CALLED',
|
1197
|
+
{
|
1198
|
+
'{file}' => FILE
|
1199
|
+
}
|
1200
|
+
)
|
1201
|
+
if defined?(@batch_events) && !@batch_events_queue.nil?
|
1202
|
+
@batch_events_queue.flush(manual: true)
|
1203
|
+
@batch_events_queue.kill_thread
|
1204
|
+
end
|
1351
1205
|
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1206
|
+
@is_opted_out = true
|
1207
|
+
@settings_file = nil
|
1208
|
+
@user_storage = nil
|
1209
|
+
@event_dispatcher = nil
|
1210
|
+
@variation_decider = nil
|
1211
|
+
@config = nil
|
1212
|
+
@usage_stats = nil
|
1213
|
+
@batch_event_dispatcher = nil
|
1214
|
+
@batch_events_queue = nil
|
1215
|
+
@batch_events = nil
|
1216
|
+
|
1217
|
+
@is_opted_out
|
1364
1218
|
end
|
1365
1219
|
|
1366
|
-
|
1367
1220
|
# Check if VWO SDK is manually opted out
|
1368
1221
|
# @param[String] :api_name api_name is used in logging
|
1369
1222
|
# @return[bool]
|
1370
|
-
def
|
1223
|
+
def opted_out?(api_name)
|
1371
1224
|
if @is_opted_out
|
1372
1225
|
@logger.log(
|
1373
1226
|
LogLevelEnum::INFO,
|
@@ -1378,10 +1231,10 @@ class VWO
|
|
1378
1231
|
}
|
1379
1232
|
)
|
1380
1233
|
end
|
1381
|
-
|
1234
|
+
@is_opted_out
|
1382
1235
|
end
|
1383
1236
|
|
1384
|
-
def
|
1385
|
-
|
1237
|
+
def event_arch_enabled?
|
1238
|
+
@settings_file.key?('isEventArchEnabled') && @settings_file['isEventArchEnabled']
|
1386
1239
|
end
|
1387
1240
|
end
|