vwo-sdk 1.14.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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