vwo-sdk 1.14.0 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53bc0be49f50d280aac4478d6879a31dce269ed69596e5ff2d04b51cbcacbcbd
4
- data.tar.gz: f28c84dc2ace873bf1c5fd748568d06c16583b466240df54fcf9dbd5dffec888
3
+ metadata.gz: 84d01560f605a69e8ed011a19ba4e3aae0f67341fd653a562d817801d6a55073
4
+ data.tar.gz: b1355bef1b2b095774c702a6757c1a7141e2cf9758d0a1b8a0510111a8ee597a
5
5
  SHA512:
6
- metadata.gz: 63bf38a8c25c69e01cf7cbfdad204379c0dd03621e947c1848a1fdf24b432bd26672a8d3cb9efded0e45582208a73a0c69142911c900e53e477e06b2d06a069e
7
- data.tar.gz: 0b9d9165ca2ae918a048537097f2de775fe13d35547c341aa45c7edc42206273775f18120c10ca06fc02821c24652bd25e513a05989889664285210b6fd57f02
6
+ metadata.gz: cc2c8a411e3c0a674ab2bc00e540b3e49a8dd943ec50aa04fba04839ef6f3e255fc275529f872aa5ca73dfe893cb43e8853a0875cc3dda9330554b6491590947
7
+ data.tar.gz: 5482e79564a365ec8fe4012b25997096352129e915daca28774c790c416a528302ea1f0bb685ef559b9ee0846b0229957a8f6ab77008f4e48222a7cae5892699
data/lib/abc.txt ADDED
@@ -0,0 +1,28 @@
1
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
2
+ GOT_ELIGIBLE_CAMPAIGNS
3
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
4
+ GOT_ELIGIBLE_CAMPAIGNS
5
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
6
+ GOT_ELIGIBLE_CAMPAIGNS
7
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
8
+ GOT_ELIGIBLE_CAMPAIGNS
9
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
10
+ GOT_ELIGIBLE_CAMPAIGNS
11
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
12
+ GOT_ELIGIBLE_CAMPAIGNS
13
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
14
+ GOT_ELIGIBLE_CAMPAIGNS
15
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
16
+ GOT_ELIGIBLE_CAMPAIGNS
17
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
18
+ GOT_ELIGIBLE_CAMPAIGNS
19
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
20
+ GOT_ELIGIBLE_CAMPAIGNS
21
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
22
+ GOT_ELIGIBLE_CAMPAIGNS
23
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
24
+ GOT_ELIGIBLE_CAMPAIGNS
25
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
26
+ GOT_ELIGIBLE_CAMPAIGNS
27
+ {"user_id"=>"Ashley", "variation_name"=>"Control", "campaign_key"=>"DEV_TEST_162"}
28
+ GOT_ELIGIBLE_CAMPAIGNS
data/lib/vwo/constants.rb CHANGED
@@ -19,6 +19,7 @@ class VWO
19
19
  SEED_VALUE = 1
20
20
  MAX_TRAFFIC_PERCENT = 100
21
21
  MAX_TRAFFIC_VALUE = 10_000
22
+ MAX_RANGE = 10000
22
23
  STATUS_RUNNING = 'RUNNING'
23
24
  # rubocop:disable Style/ExpandPathArguments
24
25
  LIBRARY_PATH = File.expand_path('../..', __FILE__)
@@ -26,7 +27,7 @@ class VWO
26
27
  HTTP_PROTOCOL = 'http://'
27
28
  HTTPS_PROTOCOL = 'https://'
28
29
  URL_NAMESPACE = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'
29
- SDK_VERSION = '1.14.0'
30
+ SDK_VERSION = '1.22.0'
30
31
  SDK_NAME = 'ruby'
31
32
  VWO_DELIMITER = '_vwo_'
32
33
  MAX_EVENTS_PER_REQUEST = 5000
@@ -68,6 +69,7 @@ class VWO
68
69
  INTEGER = 'integer'
69
70
  DOUBLE = 'double'
70
71
  BOOLEAN = 'boolean'
72
+ JSON = 'json'
71
73
  end
72
74
 
73
75
  module Hooks
@@ -80,7 +82,8 @@ class VWO
80
82
  'string' => [String],
81
83
  'integer' => [Integer],
82
84
  'double' => [Float],
83
- 'boolean' => [TrueClass, FalseClass]
85
+ 'boolean' => [TrueClass, FalseClass],
86
+ 'json' => [Hash]
84
87
  }
85
88
 
86
89
  GOAL_TYPES = {
@@ -60,7 +60,7 @@ class VWO
60
60
  end
61
61
 
62
62
  traffic_allocation = campaign['percentTraffic']
63
- value_assigned_to_user = get_bucket_value_for_user(user_id)
63
+ value_assigned_to_user = get_bucket_value_for_user(user_id, campaign)
64
64
  is_user_part = (value_assigned_to_user != 0) && value_assigned_to_user <= traffic_allocation
65
65
  @logger.log(
66
66
  LogLevelEnum::INFO,
@@ -94,7 +94,11 @@ class VWO
94
94
  return
95
95
  end
96
96
 
97
- hash_value = MurmurHash3::V32.str_hash(user_id, SEED_VALUE) & U_MAX_32_BIT
97
+ user_id_for_hash_value = user_id
98
+ if campaign[:isBucketingSeedEnabled]
99
+ user_id_for_hash_value = campaign[:id].to_s + "_" + user_id
100
+ end
101
+ hash_value = MurmurHash3::V32.str_hash(user_id_for_hash_value, SEED_VALUE) & U_MAX_32_BIT
98
102
  normalize = MAX_TRAFFIC_VALUE.to_f / campaign['percentTraffic']
99
103
  multiplier = normalize / 100
100
104
  bucket_value = get_bucket_value(
@@ -136,10 +140,17 @@ class VWO
136
140
  # User by hashing the userId by murmurHash and scaling it down.
137
141
  #
138
142
  # @param[String] :user_id The unique ID assigned to User
143
+ # @param[String] :campaign Campaign data
139
144
  # @return[Integer] The bucket Value allotted to User
140
145
  # (between 1 to $this->$MAX_TRAFFIC_PERCENT)
141
- def get_bucket_value_for_user(user_id)
142
- hash_value = MurmurHash3::V32.str_hash(user_id, SEED_VALUE) & U_MAX_32_BIT
146
+ def get_bucket_value_for_user(user_id, campaign = {}, group_id = nil, disable_logs = false)
147
+ user_id_for_hash_value = user_id
148
+ if group_id
149
+ user_id_for_hash_value = group_id.to_s + "_" + user_id
150
+ elsif campaign[:isBucketingSeedEnabled]
151
+ user_id_for_hash_value = campaign[:id].to_s + "_" + user_id
152
+ end
153
+ hash_value = MurmurHash3::V32.str_hash(user_id_for_hash_value, SEED_VALUE) & U_MAX_32_BIT
143
154
  bucket_value = get_bucket_value(hash_value, MAX_TRAFFIC_PERCENT)
144
155
 
145
156
  @logger.log(
@@ -150,7 +161,8 @@ class VWO
150
161
  hash_value: hash_value,
151
162
  bucket_value: bucket_value,
152
163
  user_id: user_id
153
- )
164
+ ),
165
+ disable_logs
154
166
  )
155
167
  bucket_value
156
168
  end
@@ -168,6 +180,22 @@ class VWO
168
180
  multiplied_value = (max_value * ratio + 1) * multiplier
169
181
  multiplied_value.to_i
170
182
  end
183
+
184
+ # Returns a campaign by checking the Start and End Bucket Allocations of each campaign.
185
+ #
186
+ # @param[Integer] :range_for_campaigns the bucket value of the user
187
+ # @param[Hash] :campaigns The bucket Value of the user
188
+ # @return[Hash|nil]
189
+ #
190
+ def get_campaign_using_range(range_for_campaigns, campaigns)
191
+ range_for_campaigns = range_for_campaigns * 100
192
+ campaigns.each do |campaign|
193
+ if campaign["max_range"] && campaign["max_range"] >= range_for_campaigns && campaign["min_range"] <= range_for_campaigns
194
+ return campaign
195
+ end
196
+ end
197
+ nil
198
+ end
171
199
  end
172
200
  end
173
201
  end
@@ -66,6 +66,8 @@ class VWO
66
66
 
67
67
  return unless campaign
68
68
 
69
+ is_campaign_part_of_group = @settings_file && is_part_of_group(@settings_file, campaign["id"])
70
+
69
71
  @has_stored_variation = false
70
72
  decision = {
71
73
  :campaign_id => campaign['id'],
@@ -93,65 +95,23 @@ class VWO
93
95
  :vwo_user_id => generator_for(user_id, @settings_file['accountId'])
94
96
  }
95
97
 
96
- if campaign['isForcedVariationEnabled']
97
- variation = evaluate_whitelisting(
98
- user_id,
99
- campaign,
100
- api_name,
101
- campaign_key,
102
- variation_targeting_variables
103
- )
104
- status = if variation
105
- StatusEnum::PASSED
106
- else
107
- StatusEnum::FAILED
108
- end
109
-
110
- @logger.log(
111
- LogLevelEnum::INFO,
112
- format(
113
- LogMessageEnum::InfoMessages::SEGMENTATION_STATUS,
114
- file: FILE,
115
- campaign_key: campaign_key,
116
- user_id: user_id,
117
- status: status,
118
- custom_variables: variation_targeting_variables,
119
- variation_name: status == StatusEnum::PASSED ? "and #{variation['name']} is Assigned" : ' ',
120
- segmentation_type: SegmentationTypeEnum::WHITELISTING,
121
- api_name: api_name
122
- )
123
- )
124
-
125
- if variation
126
- if campaign['type'] == CampaignTypes::VISUAL_AB || campaign['type'] == CampaignTypes::FEATURE_TEST
127
- decision[:variation_name] = variation['name']
128
- decision[:variation_id] = variation['id']
129
- if campaign['type'] == CampaignTypes::FEATURE_TEST
130
- decision[:is_feature_enabled] = variation['isFeatureEnabled']
131
- elsif campaign['type'] == CampaignTypes::VISUAL_AB
132
- decision[:is_user_whitelisted] = !!variation['name']
133
- end
134
- end
135
- @hooks_manager.execute(decision)
136
- end
137
-
138
- return variation if variation && variation['name']
139
- else
140
- @logger.log(
141
- LogLevelEnum::INFO,
142
- format(
143
- LogMessageEnum::InfoMessages::WHITELISTING_SKIPPED,
144
- file: FILE,
145
- campaign_key: campaign_key,
146
- user_id: user_id,
147
- api_name: api_name
148
- )
149
- )
98
+ if is_campaign_part_of_group
99
+ group_id = @settings_file["campaignGroups"][campaign["id"].to_s]
100
+ decision[:group_id] = group_id
101
+ group_name = @settings_file["groups"][group_id.to_s]["name"]
102
+ decision[:group_name] = group_name
150
103
  end
151
104
 
105
+ # evaluate whitelisting
106
+ variation = get_variation_if_whitelisting_passed(user_id, campaign, variation_targeting_variables, api_name, decision, true)
107
+ return variation if variation && variation['name']
108
+
152
109
  user_campaign_map = get_user_storage(user_id, campaign_key)
153
110
  variation = get_stored_variation(user_id, campaign_key, user_campaign_map) if valid_hash?(user_campaign_map)
154
- variation = variation.dup # deep copy
111
+
112
+ if variation
113
+ variation = variation.dup # deep copy
114
+ end
155
115
 
156
116
  if variation
157
117
  if valid_string?(user_campaign_map['goal_identifier']) && api_name == ApiMethods::TRACK
@@ -191,8 +151,7 @@ class VWO
191
151
  )
192
152
  )
193
153
 
194
- if ([ApiMethods::TRACK, ApiMethods::GET_VARIATION_NAME, ApiMethods::GET_FEATURE_VARIABLE_VALUE].include? api_name) &&
195
- @user_storage_service && campaign['type'] != CampaignTypes::FEATURE_ROLLOUT
154
+ if ([ApiMethods::TRACK, ApiMethods::GET_VARIATION_NAME, ApiMethods::GET_FEATURE_VARIABLE_VALUE].include? api_name) && @user_storage_service
196
155
  @logger.log(
197
156
  LogLevelEnum::DEBUG,
198
157
  format(
@@ -220,82 +179,106 @@ class VWO
220
179
  end
221
180
 
222
181
  # Pre-segmentation
182
+ is_presegmentation = check_presegmentation(campaign, user_id, custom_variables, api_name)
183
+ is_presegmentation_and_traffic_passed = is_presegmentation && @bucketer.user_part_of_campaign?(user_id, campaign)
184
+ unless is_presegmentation_and_traffic_passed
185
+ return nil
186
+ end
223
187
 
224
- segments = get_segments(campaign)
225
- is_valid_segments = valid_value?(segments)
188
+ if is_presegmentation_and_traffic_passed && is_campaign_part_of_group
189
+ group_campaigns = get_group_campaigns(@settings_file, group_id)
190
+
191
+ if group_campaigns
192
+ is_any_campaign_whitelisted_or_stored = check_whitelisting_or_storage_for_grouped_campaigns(user_id, campaign, group_campaigns, group_name, variation_targeting_variables, true)
193
+
194
+ if is_any_campaign_whitelisted_or_stored
195
+ @logger.log(
196
+ LogLevelEnum::INFO,
197
+ format(
198
+ LogMessageEnum::InfoMessages::CALLED_CAMPAIGN_NOT_WINNER,
199
+ file: FILE,
200
+ campaign_key: campaign_key,
201
+ user_id: user_id,
202
+ group_name: group_name
203
+ )
204
+ )
205
+ return nil
206
+ end
207
+
208
+ eligible_campaigns = get_eligible_campaigns(user_id, group_campaigns, campaign, custom_variables)
209
+ non_eligible_campaigns_key = get_non_eligible_campaigns_key(eligible_campaigns, group_campaigns)
210
+
211
+ @logger.log(
212
+ LogLevelEnum::DEBUG,
213
+ format(
214
+ LogMessageEnum::DebugMessages::GOT_ELIGIBLE_CAMPAIGNS,
215
+ file: FILE,
216
+ user_id: user_id,
217
+ eligible_campaigns_key: get_eligible_campaigns_key(eligible_campaigns).join(","),
218
+ ineligible_campaigns_log_text: non_eligible_campaigns_key ? ("campaigns:" + non_eligible_campaigns_key.join("'")) : "no campaigns",
219
+ group_name: group_name
220
+ )
221
+ )
226
222
 
227
- if is_valid_segments
228
- unless custom_variables
229
223
  @logger.log(
230
224
  LogLevelEnum::INFO,
231
225
  format(
232
- LogMessageEnum::InfoMessages::NO_CUSTOM_VARIABLES,
226
+ LogMessageEnum::InfoMessages::GOT_ELIGIBLE_CAMPAIGNS,
233
227
  file: FILE,
234
- campaign_key: campaign_key,
235
228
  user_id: user_id,
236
- api_name: api_name
229
+ no_of_eligible_campaigns: eligible_campaigns.length,
230
+ no_of_group_campaigns: group_campaigns.length,
231
+ group_name: group_name
237
232
  )
238
233
  )
239
- custom_variables = {}
240
- end
241
- unless @segment_evaluator.evaluate(campaign_key, user_id, segments, custom_variables)
234
+
235
+ winner_campaign = get_winner_campaign(user_id, eligible_campaigns, group_id)
242
236
  @logger.log(
243
237
  LogLevelEnum::INFO,
244
238
  format(
245
- LogMessageEnum::InfoMessages::USER_FAILED_SEGMENTATION,
246
- file: FileNameEnum::SegmentEvaluator,
239
+ LogMessageEnum::InfoMessages::GOT_WINNER_CAMPAIGN,
240
+ file: FILE,
247
241
  user_id: user_id,
248
- campaign_key: campaign_key,
249
- custom_variables: custom_variables
242
+ campaign_key: winner_campaign["key"],
243
+ group_name: group_name
250
244
  )
251
245
  )
252
- return
246
+
247
+ if winner_campaign && winner_campaign["id"] == campaign["id"]
248
+ variation = get_variation_allotted(user_id, campaign, true)
249
+ if variation && variation['name']
250
+ save_user_storage(user_id, campaign_key, campaign['type'], variation['name'], goal_identifier, true) if variation['name']
251
+ else
252
+ return nil
253
+ end
254
+ else
255
+ @logger.log(
256
+ LogLevelEnum::INFO,
257
+ format(
258
+ LogMessageEnum::InfoMessages::CALLED_CAMPAIGN_NOT_WINNER,
259
+ file: FILE,
260
+ campaign_key: campaign_key,
261
+ user_id: user_id,
262
+ group_name: group_name
263
+ )
264
+ )
265
+ return nil
266
+ end
253
267
  end
254
- @logger.log(
255
- LogLevelEnum::INFO,
256
- format(
257
- LogMessageEnum::InfoMessages::USER_PASSED_SEGMENTATION,
258
- file: FileNameEnum::SegmentEvaluator,
259
- user_id: user_id,
260
- campaign_key: campaign_key,
261
- custom_variables: custom_variables
262
- )
263
- )
264
- else
265
- @logger.log(
266
- LogLevelEnum::INFO,
267
- format(
268
- LogMessageEnum::InfoMessages::SKIPPING_SEGMENTATION,
269
- file: FILE,
270
- campaign_key: campaign_key,
271
- user_id: user_id,
272
- api_name: api_name,
273
- variation: ''
274
- )
275
- )
276
268
  end
277
269
 
278
- variation = get_variation_allotted(user_id, campaign)
279
-
280
- if variation && variation['name']
281
- save_user_storage(user_id, campaign_key, variation['name'], goal_identifier) if variation['name']
270
+ if variation.nil?
271
+ variation = get_variation_allotted(user_id, campaign)
282
272
 
283
- @logger.log(
284
- LogLevelEnum::INFO,
285
- format(
286
- LogMessageEnum::InfoMessages::VARIATION_ALLOCATED,
287
- file: FILE,
288
- campaign_key: campaign_key,
289
- user_id: user_id,
290
- variation_name: variation['name'],
291
- campaign_type: campaign['type']
273
+ if variation && variation['name']
274
+ save_user_storage(user_id, campaign_key, campaign['type'], variation['name'], goal_identifier) if variation['name']
275
+ else
276
+ @logger.log(
277
+ LogLevelEnum::INFO,
278
+ format(LogMessageEnum::InfoMessages::NO_VARIATION_ALLOCATED, file: FILE, campaign_key: campaign_key, user_id: user_id)
292
279
  )
293
- )
294
- else
295
- @logger.log(
296
- LogLevelEnum::INFO,
297
- format(LogMessageEnum::InfoMessages::NO_VARIATION_ALLOCATED, file: FILE, campaign_key: campaign_key, user_id: user_id)
298
- )
280
+ end
281
+
299
282
  end
300
283
 
301
284
  if variation
@@ -318,7 +301,7 @@ class VWO
318
301
  #
319
302
  # @return[Hash]
320
303
 
321
- def get_variation_allotted(user_id, campaign)
304
+ def get_variation_allotted(user_id, campaign, disable_logs = false)
322
305
  unless valid_value?(user_id)
323
306
  @logger.log(
324
307
  LogLevelEnum::ERROR,
@@ -338,7 +321,8 @@ class VWO
338
321
  user_id: user_id,
339
322
  campaign_key: campaign['key'],
340
323
  method: 'get_variation_allotted'
341
- )
324
+ ),
325
+ disable_logs
342
326
  )
343
327
  variation
344
328
  else
@@ -351,7 +335,8 @@ class VWO
351
335
  user_id: user_id,
352
336
  campaign_key: nil,
353
337
  method: 'get_variation_allotted'
354
- )
338
+ ),
339
+ disable_logs
355
340
  )
356
341
  nil
357
342
  end
@@ -410,13 +395,15 @@ class VWO
410
395
  # @param[String] :campaign_key Unique campaign identifier
411
396
  # @param[String] :variation_name Variation identifier
412
397
  # @param[String] :goal_identifier The unique campaign's goal identifier
398
+ # @param[Boolean] :disable_logs optional: disable logs if True
413
399
  # @return[Boolean] true if found otherwise false
414
400
 
415
- def save_user_storage(user_id, campaign_key, variation_name, goal_identifier)
401
+ def save_user_storage(user_id, campaign_key, campaign_type, variation_name, goal_identifier, disable_logs = false)
416
402
  unless @user_storage_service
417
403
  @logger.log(
418
404
  LogLevelEnum::DEBUG,
419
- format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_SAVE, file: FILE)
405
+ format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_SAVE, file: FILE),
406
+ disable_logs
420
407
  )
421
408
  return false
422
409
  end
@@ -432,13 +419,28 @@ class VWO
432
419
 
433
420
  @logger.log(
434
421
  LogLevelEnum::INFO,
435
- format(LogMessageEnum::InfoMessages::SAVING_DATA_USER_STORAGE_SERVICE, file: FILE, user_id: user_id)
422
+ format(LogMessageEnum::InfoMessages::SAVING_DATA_USER_STORAGE_SERVICE, file: FILE, user_id: user_id),
423
+ disable_logs
424
+ )
425
+
426
+ @logger.log(
427
+ LogLevelEnum::INFO,
428
+ format(
429
+ LogMessageEnum::InfoMessages::VARIATION_ALLOCATED,
430
+ file: FILE,
431
+ campaign_key: campaign_key,
432
+ user_id: user_id,
433
+ variation_name: variation_name,
434
+ campaign_type: campaign_type
435
+ ),
436
+ disable_logs
436
437
  )
437
438
  true
438
439
  rescue StandardError
439
440
  @logger.log(
440
441
  LogLevelEnum::ERROR,
441
- format(LogMessageEnum::ErrorMessages::SAVE_USER_STORAGE_SERVICE_FAILED, file: FILE, user_id: user_id)
442
+ format(LogMessageEnum::ErrorMessages::SAVE_USER_STORAGE_SERVICE_FAILED, file: FILE, user_id: user_id),
443
+ disable_logs
442
444
  )
443
445
  false
444
446
  end
@@ -452,10 +454,11 @@ class VWO
452
454
  # @param[String] :api_name The key Passed to identify the calling API
453
455
  # @param[String] :campaign_key Unique campaign key
454
456
  # @param[Hash] :variation_targeting_variables Key/value pair of Whitelisting Custom Attributes
457
+ # @param[Boolean] :disable_logs optional: disable logs if True
455
458
  #
456
459
  # @return[Hash]
457
460
 
458
- def evaluate_whitelisting(user_id, campaign, api_name, campaign_key, variation_targeting_variables = {})
461
+ def evaluate_whitelisting(user_id, campaign, api_name, campaign_key, variation_targeting_variables = {}, disable_logs = false)
459
462
  if variation_targeting_variables.nil?
460
463
  variation_targeting_variables = { '_vwo_user_id' => user_id }
461
464
  else
@@ -467,7 +470,7 @@ class VWO
467
470
  segments = get_segments(variation)
468
471
  is_valid_segments = valid_value?(segments)
469
472
  if is_valid_segments
470
- if @segment_evaluator.evaluate(campaign_key, user_id, segments, variation_targeting_variables)
473
+ if @segment_evaluator.evaluate(campaign_key, user_id, segments, variation_targeting_variables, disable_logs)
471
474
  targeted_variations.push(variation)
472
475
  status = StatusEnum::PASSED
473
476
  else
@@ -485,7 +488,8 @@ class VWO
485
488
  variation_name: variation['name'],
486
489
  segmentation_type: SegmentationTypeEnum::WHITELISTING,
487
490
  api_name: api_name
488
- )
491
+ ),
492
+ disable_logs
489
493
  )
490
494
  else
491
495
  @logger.log(
@@ -497,7 +501,8 @@ class VWO
497
501
  user_id: user_id,
498
502
  api_name: api_name,
499
503
  variation: variation['name']
500
- )
504
+ ),
505
+ disable_logs
501
506
  )
502
507
  end
503
508
  end
@@ -522,7 +527,8 @@ class VWO
522
527
  whitelisted_variation = @bucketer.get_variation(
523
528
  targeted_variations_deep_clone,
524
529
  @bucketer.get_bucket_value_for_user(
525
- user_id
530
+ user_id,
531
+ campaign
526
532
  )
527
533
  )
528
534
  else
@@ -550,18 +556,26 @@ class VWO
550
556
  end
551
557
  end
552
558
 
559
+ def scale_campaigns_weight(campaigns)
560
+ normalize_weight = 100/campaigns.length
561
+ campaigns.each do |campaign|
562
+ campaign['weight'] = normalize_weight
563
+ end
564
+ end
553
565
  # Get the UserStorageData after looking up into get method
554
566
  # Being provided via UserStorageService
555
567
  #
556
568
  # @param[String]: Unique user identifier
557
569
  # @param[String]: Unique campaign key
570
+ # @param[Boolean] :disable_logs if True
558
571
  # @return[Hash|Boolean]: user_storage data
559
572
 
560
- def get_user_storage(user_id, campaign_key)
573
+ def get_user_storage(user_id, campaign_key, disable_logs = false)
561
574
  unless @user_storage_service
562
575
  @logger.log(
563
576
  LogLevelEnum::DEBUG,
564
- format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_LOOKUP, file: FILE)
577
+ format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_LOOKUP, file: FILE),
578
+ disable_logs
565
579
  )
566
580
  return false
567
581
  end
@@ -574,13 +588,15 @@ class VWO
574
588
  file: FILE,
575
589
  user_id: user_id,
576
590
  status: data.nil? ? 'Not Found' : 'Found'
577
- )
591
+ ),
592
+ disable_logs
578
593
  )
579
594
  data
580
595
  rescue StandardError
581
596
  @logger.log(
582
597
  LogLevelEnum::ERROR,
583
- format(LogMessageEnum::ErrorMessages::LOOK_UP_USER_STORAGE_SERVICE_FAILED, file: FILE, user_id: user_id)
598
+ format(LogMessageEnum::ErrorMessages::LOOK_UP_USER_STORAGE_SERVICE_FAILED, file: FILE, user_id: user_id),
599
+ disable_logs
584
600
  )
585
601
  false
586
602
  end
@@ -590,10 +606,11 @@ class VWO
590
606
  # @param[String] :user_id
591
607
  # @param[String] :campaign_key campaign identified
592
608
  # @param[Hash] :user_campaign_map BucketMap consisting of stored user variation
609
+ # @param[Boolean] :disable_logs if True
593
610
  #
594
611
  # @return[Object, nil] if found then variation settings object otherwise None
595
612
 
596
- def get_stored_variation(user_id, campaign_key, user_campaign_map)
613
+ def get_stored_variation(user_id, campaign_key, user_campaign_map, disable_logs = false)
597
614
  return unless user_campaign_map['campaign_key'] == campaign_key
598
615
 
599
616
  variation_name = user_campaign_map['variation_name']
@@ -605,7 +622,8 @@ class VWO
605
622
  campaign_key: campaign_key,
606
623
  user_id: user_id,
607
624
  variation_name: variation_name
608
- )
625
+ ),
626
+ disable_logs
609
627
  )
610
628
 
611
629
  get_campaign_variation(
@@ -614,6 +632,277 @@ class VWO
614
632
  variation_name
615
633
  )
616
634
  end
635
+
636
+ # this function check whether pre-segmentation is passed or not
637
+ #
638
+ # @param[String] :user_id The unique key assigned to User
639
+ # @param[Hash] :campaign Campaign hash for Unique campaign key
640
+ # @param[Hash] :custom_variables Key/value pair for segmentation
641
+ # @param[String] :api_name The key Passed to identify the calling API
642
+ # @param[Boolean] :disable_logs optional: disable logs if True
643
+ #
644
+ # @return[Boolean]
645
+ def check_presegmentation(campaign, user_id, custom_variables, api_name, disable_logs = false)
646
+ campaign_key = campaign['key']
647
+ segments = get_segments(campaign)
648
+ is_valid_segments = valid_value?(segments)
649
+
650
+ if is_valid_segments
651
+ unless custom_variables
652
+ @logger.log(
653
+ LogLevelEnum::INFO,
654
+ format(
655
+ LogMessageEnum::InfoMessages::NO_CUSTOM_VARIABLES,
656
+ file: FILE,
657
+ campaign_key: campaign_key,
658
+ user_id: user_id,
659
+ api_name: api_name
660
+ ),
661
+ disable_logs
662
+ )
663
+ custom_variables = {}
664
+ end
665
+ unless @segment_evaluator.evaluate(campaign_key, user_id, segments, custom_variables, disable_logs)
666
+ @logger.log(
667
+ LogLevelEnum::INFO,
668
+ format(
669
+ LogMessageEnum::InfoMessages::USER_FAILED_SEGMENTATION,
670
+ file: FileNameEnum::SegmentEvaluator,
671
+ user_id: user_id,
672
+ campaign_key: campaign_key,
673
+ custom_variables: custom_variables
674
+ ),
675
+ disable_logs
676
+ )
677
+ return false
678
+ end
679
+ @logger.log(
680
+ LogLevelEnum::INFO,
681
+ format(
682
+ LogMessageEnum::InfoMessages::USER_PASSED_SEGMENTATION,
683
+ file: FileNameEnum::SegmentEvaluator,
684
+ user_id: user_id,
685
+ campaign_key: campaign_key,
686
+ custom_variables: custom_variables
687
+ ),
688
+ disable_logs
689
+ )
690
+ else
691
+ @logger.log(
692
+ LogLevelEnum::INFO,
693
+ format(
694
+ LogMessageEnum::InfoMessages::SKIPPING_SEGMENTATION,
695
+ file: FILE,
696
+ campaign_key: campaign_key,
697
+ user_id: user_id,
698
+ api_name: api_name,
699
+ variation: ''
700
+ ),
701
+ disable_logs
702
+ )
703
+ end
704
+ true
705
+ end
706
+
707
+ # Finds and returns eligible campaigns from group_campaigns.
708
+ #
709
+ # @param[String] :user_id The unique key assigned to User
710
+ # @param[Hash] :called_campaign campaign for which api is called
711
+ # @param[Array] :group_campaigns campaigns part of group
712
+ # @param[String] :custom_variables Key/value pair for segmentation
713
+ #
714
+ # @return[Array]
715
+ def get_eligible_campaigns(user_id, group_campaigns, called_campaign, custom_variables)
716
+ eligible_campaigns = []
717
+
718
+ group_campaigns.each do |campaign|
719
+ if called_campaign["id"] == campaign["id"] || check_presegmentation(campaign, user_id, custom_variables, '', true) && @bucketer.user_part_of_campaign?(user_id, campaign)
720
+ eligible_campaigns.append(campaign)
721
+ end
722
+ end
723
+ return eligible_campaigns
724
+ end
725
+
726
+ # Finds and returns the winner campaign from eligible_campaigns list.
727
+ #
728
+ # @param[String] :user_id The unique key assigned to User
729
+ # @param[Array] :eligible_campaigns campaigns part of group which were eligible to be winner
730
+ #
731
+ # @return[Hash]
732
+ def get_winner_campaign(user_id, eligible_campaigns, group_id)
733
+ if eligible_campaigns.length == 1
734
+ return eligible_campaigns[0]
735
+ end
736
+
737
+ eligible_campaigns = scale_campaigns_weight(eligible_campaigns)
738
+ eligible_campaigns = set_campaign_allocation(eligible_campaigns)
739
+ bucket_value = @bucketer.get_bucket_value_for_user(user_id, {}, group_id, true)
740
+ return @bucketer.get_campaign_using_range(bucket_value, eligible_campaigns)
741
+ end
742
+
743
+ # Get campaign keys of all eligible Campaigns.
744
+ #
745
+ # @param[Array] :eligible_campaigns campaigns part of group which were eligible to be winner
746
+ #
747
+ # @return[Array]
748
+ def get_eligible_campaigns_key(eligible_campaigns)
749
+ eligible_campaigns_key = []
750
+ eligible_campaigns.each do |campaign|
751
+ eligible_campaigns_key.append(campaign["key"])
752
+ end
753
+ eligible_campaigns_key
754
+ end
755
+
756
+ # Get campaign keys of all non eligible Campaigns.
757
+ #
758
+ # @param[Array] :eligible_campaigns campaigns part of group which were eligible to be winner
759
+ # @param[Array] :group_campaigns campaigns part of group
760
+ #
761
+ # @return[Array]
762
+ def get_non_eligible_campaigns_key(eligible_campaigns, group_campaigns)
763
+ non_eligible_campaigns_key = []
764
+ group_campaigns.each do |campaign|
765
+ unless eligible_campaigns.include? campaign
766
+ non_eligible_campaigns_key.append(campaign["key"])
767
+ end
768
+ end
769
+ non_eligible_campaigns_key
770
+ end
771
+
772
+ # Checks if any other campaign in groupCampaigns satisfies whitelisting or is in user storage.
773
+ #
774
+ # @param[String] :user_id the unique ID assigned to User
775
+ # @param[Hash] :called_campaign campaign for which api is called
776
+ # @param[Array] :group_campaigns campaigns part of group
777
+ # @param[String] :group_name group name
778
+ # @param[Hash] :variation_targeting_variables Key/value pair of Whitelisting Custom Attributes
779
+ # @param[Boolean] :disable_logs optional: disable logs if True
780
+ # @return[Boolean]
781
+
782
+ def check_whitelisting_or_storage_for_grouped_campaigns(user_id, called_campaign, group_campaigns, group_name, variation_targeting_variables, disable_logs = false)
783
+ group_campaigns.each do |campaign|
784
+ if called_campaign["id"] != campaign["id"]
785
+ targeted_variation = evaluate_whitelisting(
786
+ user_id,
787
+ campaign,
788
+ '',
789
+ campaign["key"],
790
+ variation_targeting_variables,
791
+ true
792
+ )
793
+ if targeted_variation
794
+ @logger.log(
795
+ LogLevelEnum::INFO,
796
+ format(
797
+ LogMessageEnum::InfoMessages::OTHER_CAMPAIGN_SATISFIES_WHITELISTING_OR_STORAGE,
798
+ file: FILE,
799
+ campaign_key: campaign["key"],
800
+ user_id: user_id,
801
+ group_name: group_name,
802
+ type: "whitelisting"
803
+ ),
804
+ disable_logs
805
+ )
806
+ return true
807
+ end
808
+ end
809
+ end
810
+
811
+ group_campaigns.each do |campaign|
812
+ if called_campaign["id"] != campaign["id"]
813
+ user_storage_data = get_user_storage(user_id, campaign["key"], true)
814
+ if user_storage_data
815
+ @logger.log(
816
+ LogLevelEnum::INFO,
817
+ format(
818
+ LogMessageEnum::InfoMessages::OTHER_CAMPAIGN_SATISFIES_WHITELISTING_OR_STORAGE,
819
+ file: FILE,
820
+ campaign_key: campaign["key"],
821
+ user_id: user_id,
822
+ group_name: group_name,
823
+ type: "user storage"
824
+ ),
825
+ disable_logs
826
+ )
827
+ return true
828
+ end
829
+ end
830
+ end
831
+ false
832
+ end
833
+
834
+ # Get variation if whitelisting passes
835
+ #
836
+ # @param[String] :user_id the unique ID assigned to User
837
+ # @param[Hash] :campaign campaign for which checking whitelisting
838
+ # @param[Hash] :variation_targeting_variables Key/value pair of Whitelisting Custom Attributes
839
+ # @param[String] :api_name The key Passed to identify the calling API
840
+ # @param[Hash] :decision data containing campaign info passed to hooks manager
841
+ # @param[Boolean] :disable_logs optional: disable logs if True
842
+ # @return[Hash]
843
+ def get_variation_if_whitelisting_passed(user_id, campaign, variation_targeting_variables, api_name, decision, disable_logs = false)
844
+ campaign_key = campaign['key']
845
+ if campaign['isForcedVariationEnabled']
846
+ variation = evaluate_whitelisting(
847
+ user_id,
848
+ campaign,
849
+ api_name,
850
+ campaign_key,
851
+ variation_targeting_variables,
852
+ disable_logs
853
+ )
854
+ status = if variation
855
+ StatusEnum::PASSED
856
+ else
857
+ StatusEnum::FAILED
858
+ end
859
+
860
+ @logger.log(
861
+ LogLevelEnum::INFO,
862
+ format(
863
+ LogMessageEnum::InfoMessages::SEGMENTATION_STATUS,
864
+ file: FILE,
865
+ campaign_key: campaign_key,
866
+ user_id: user_id,
867
+ status: status,
868
+ custom_variables: variation_targeting_variables,
869
+ variation_name: status == StatusEnum::PASSED ? "and #{variation['name']} is Assigned" : ' ',
870
+ segmentation_type: SegmentationTypeEnum::WHITELISTING,
871
+ api_name: api_name
872
+ ),
873
+ disable_logs
874
+ )
875
+
876
+ if variation
877
+ if campaign['type'] == CampaignTypes::VISUAL_AB || campaign['type'] == CampaignTypes::FEATURE_TEST
878
+ decision[:variation_name] = variation['name']
879
+ decision[:variation_id] = variation['id']
880
+ if campaign['type'] == CampaignTypes::FEATURE_TEST
881
+ decision[:is_feature_enabled] = variation['isFeatureEnabled']
882
+ elsif campaign['type'] == CampaignTypes::VISUAL_AB
883
+ decision[:is_user_whitelisted] = !!variation['name']
884
+ end
885
+ end
886
+ @hooks_manager.execute(decision)
887
+ end
888
+
889
+ return variation if variation && variation['name']
890
+ else
891
+ @logger.log(
892
+ LogLevelEnum::INFO,
893
+ format(
894
+ LogMessageEnum::InfoMessages::WHITELISTING_SKIPPED,
895
+ file: FILE,
896
+ campaign_key: campaign_key,
897
+ user_id: user_id,
898
+ api_name: api_name
899
+ ),
900
+ disable_logs
901
+ )
902
+ end
903
+ nil
904
+ end
905
+
617
906
  end
618
907
  end
619
908
  end