vwo-sdk 1.35.0 → 1.38.0
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 +213 -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
@@ -33,7 +33,7 @@ class VWO
|
|
33
33
|
include VWO::CONSTANTS
|
34
34
|
include VWO::Utils::UUID
|
35
35
|
|
36
|
-
FILE = FileNameEnum::
|
36
|
+
FILE = FileNameEnum::VARIATION_DECIDER
|
37
37
|
|
38
38
|
# Initializes various services
|
39
39
|
# @param[Hash] - Settings file
|
@@ -66,43 +66,17 @@ class VWO
|
|
66
66
|
|
67
67
|
return unless campaign
|
68
68
|
|
69
|
-
is_campaign_part_of_group = @settings_file &&
|
69
|
+
is_campaign_part_of_group = @settings_file && part_of_group?(@settings_file, campaign['id'])
|
70
70
|
|
71
71
|
@has_stored_variation = false
|
72
|
-
decision =
|
73
|
-
:campaign_id => campaign['id'],
|
74
|
-
:campaign_key => campaign_key,
|
75
|
-
:campaign_type => campaign['type'],
|
76
|
-
# campaign segmentation conditions
|
77
|
-
:custom_variables => custom_variables,
|
78
|
-
# event name
|
79
|
-
:event => Hooks::DECISION_TYPES['CAMPAIGN_DECISION'],
|
80
|
-
# goal tracked in case of track API
|
81
|
-
:goal_identifier => goal_identifier,
|
82
|
-
# campaign whitelisting flag
|
83
|
-
:is_forced_variation_enabled => campaign['isForcedVariationEnabled'] ? campaign['isForcedVariationEnabled'] : false,
|
84
|
-
:sdk_version => SDK_VERSION,
|
85
|
-
# API name which triggered the event
|
86
|
-
:source => api_name,
|
87
|
-
# Passed in API
|
88
|
-
:user_id => user_id,
|
89
|
-
# Campaign Whitelisting conditions
|
90
|
-
:variation_targeting_variables => variation_targeting_variables,
|
91
|
-
:is_user_whitelisted => false,
|
92
|
-
:from_user_storage_service => false,
|
93
|
-
:is_feature_enabled => true,
|
94
|
-
# VWO generated UUID based on passed UserId and Account ID
|
95
|
-
:vwo_user_id => generator_for(user_id, @settings_file['accountId'])
|
96
|
-
}
|
72
|
+
decision = initialize_decision_properties(user_id, campaign, api_name, custom_variables, variation_targeting_variables, goal_identifier)
|
97
73
|
|
98
|
-
if campaign.
|
99
|
-
decision[:campaign_name] = campaign['name']
|
100
|
-
end
|
74
|
+
decision[:campaign_name] = campaign['name'] if campaign.key?('name')
|
101
75
|
|
102
76
|
if is_campaign_part_of_group
|
103
|
-
group_id = @settings_file[
|
77
|
+
group_id = @settings_file['campaignGroups'][campaign['id'].to_s]
|
104
78
|
decision[:group_id] = group_id
|
105
|
-
group_name = @settings_file[
|
79
|
+
group_name = @settings_file['groups'][group_id.to_s]['name']
|
106
80
|
decision[:group_name] = group_name
|
107
81
|
end
|
108
82
|
|
@@ -110,21 +84,17 @@ class VWO
|
|
110
84
|
variation = get_variation_if_whitelisting_passed(user_id, campaign, variation_targeting_variables, api_name, decision, true)
|
111
85
|
return variation if variation && variation['name']
|
112
86
|
|
113
|
-
if campaign.
|
114
|
-
is_presegmentation =
|
115
|
-
return
|
87
|
+
if campaign.key?('isAlwaysCheckSegment')
|
88
|
+
is_presegmentation = presegmentation?(campaign, user_id, custom_variables, api_name)
|
89
|
+
return get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision)
|
116
90
|
else
|
117
91
|
user_campaign_map = get_user_storage(user_id, campaign_key)
|
118
92
|
variation = get_stored_variation(user_id, campaign_key, user_campaign_map) if valid_hash?(user_campaign_map)
|
119
93
|
|
94
|
+
variation = variation.dup if variation # deep copy
|
95
|
+
|
120
96
|
if variation
|
121
|
-
variation =
|
122
|
-
end
|
123
|
-
|
124
|
-
if variation
|
125
|
-
if valid_string?(user_campaign_map['goal_identifier']) && api_name == ApiMethods::TRACK
|
126
|
-
variation['goal_identifier'] = user_campaign_map['goal_identifier']
|
127
|
-
end
|
97
|
+
variation['goal_identifier'] = user_campaign_map['goal_identifier'] if valid_string?(user_campaign_map['goal_identifier']) && api_name == ApiMethods::TRACK
|
128
98
|
@has_stored_variation = true
|
129
99
|
@logger.log(
|
130
100
|
LogLevelEnum::INFO,
|
@@ -137,16 +107,8 @@ class VWO
|
|
137
107
|
}
|
138
108
|
)
|
139
109
|
decision[:from_user_storage_service] = !!variation['name']
|
140
|
-
|
141
|
-
|
142
|
-
decision[:variation_name] = variation['name']
|
143
|
-
decision[:variation_id] = variation['id']
|
144
|
-
if campaign['type'] == CampaignTypes::FEATURE_TEST
|
145
|
-
decision[:is_feature_enabled] = variation['isFeatureEnabled']
|
146
|
-
end
|
147
|
-
end
|
148
|
-
@hooks_manager.execute(decision)
|
149
|
-
end
|
110
|
+
decision = add_variation_to_decision_properties(decision, campaign, variation)
|
111
|
+
@hooks_manager.execute(decision)
|
150
112
|
return variation
|
151
113
|
else
|
152
114
|
@logger.log(
|
@@ -158,48 +120,20 @@ class VWO
|
|
158
120
|
'{userId}' => user_id
|
159
121
|
}
|
160
122
|
)
|
161
|
-
|
162
|
-
if (
|
163
|
-
@logger.log(
|
164
|
-
LogLevelEnum::WARNING,
|
165
|
-
'CAMPAIGN_NOT_ACTIVATED',
|
166
|
-
{
|
167
|
-
'{file}' => FILE,
|
168
|
-
'{campaignKey}' => campaign_key,
|
169
|
-
'{userId}' => user_id,
|
170
|
-
'{api}' => api_name
|
171
|
-
}
|
172
|
-
)
|
173
|
-
|
174
|
-
@logger.log(
|
175
|
-
LogLevelEnum::INFO,
|
176
|
-
'CAMPAIGN_NOT_ACTIVATED',
|
177
|
-
{
|
178
|
-
'{file}' => FILE,
|
179
|
-
'{campaignKey}' => campaign_key,
|
180
|
-
'{userId}' => user_id,
|
181
|
-
'{reason}' => api_name == ApiMethods::TRACK ? 'track it' : 'get the decision/value'
|
182
|
-
}
|
183
|
-
)
|
184
|
-
return
|
185
|
-
end
|
123
|
+
|
124
|
+
return if campaign_not_activated?(user_id, campaign_key, api_name)
|
186
125
|
end
|
187
126
|
end
|
188
127
|
|
189
|
-
|
190
|
-
|
191
128
|
# Pre-segmentation
|
192
|
-
is_presegmentation =
|
129
|
+
is_presegmentation = presegmentation?(campaign, user_id, custom_variables, api_name)
|
193
130
|
is_presegmentation_and_traffic_passed = is_presegmentation && @bucketer.user_part_of_campaign?(user_id, campaign)
|
194
|
-
unless is_presegmentation_and_traffic_passed
|
195
|
-
return nil
|
196
|
-
end
|
131
|
+
return nil unless is_presegmentation_and_traffic_passed
|
197
132
|
|
198
133
|
if is_presegmentation_and_traffic_passed && is_campaign_part_of_group
|
199
134
|
group_campaigns = get_group_campaigns(@settings_file, group_id)
|
200
135
|
if group_campaigns
|
201
|
-
|
202
|
-
if is_any_campaign_whitelisted_or_stored
|
136
|
+
if whitelisting_or_storage_for_grouped_campaigns?(user_id, campaign, group_campaigns, group_name, variation_targeting_variables, true)
|
203
137
|
@logger.log(
|
204
138
|
LogLevelEnum::INFO,
|
205
139
|
'MEG_CALLED_CAMPAIGN_NOT_WINNER',
|
@@ -207,7 +141,7 @@ class VWO
|
|
207
141
|
'{file}' => FILE,
|
208
142
|
'{campaignKey}' => campaign_key,
|
209
143
|
'{userId}' => user_id,
|
210
|
-
'{groupName}' => group_name
|
144
|
+
'{groupName}' => group_name
|
211
145
|
}
|
212
146
|
)
|
213
147
|
return nil
|
@@ -220,8 +154,8 @@ class VWO
|
|
220
154
|
{
|
221
155
|
'{file}' => FILE,
|
222
156
|
'{userId}' => user_id,
|
223
|
-
'{eligibleCampaignKeys}' => get_eligible_campaigns_key(eligible_campaigns).join(
|
224
|
-
'{inEligibleText}' => non_eligible_campaigns_key ?
|
157
|
+
'{eligibleCampaignKeys}' => get_eligible_campaigns_key(eligible_campaigns).join(','),
|
158
|
+
'{inEligibleText}' => non_eligible_campaigns_key ? "campaigns: + #{non_eligible_campaigns_key.join("'")}" : 'no campaigns',
|
225
159
|
'{groupName}' => group_name
|
226
160
|
}
|
227
161
|
)
|
@@ -245,47 +179,120 @@ class VWO
|
|
245
179
|
{
|
246
180
|
'{file}' => FILE,
|
247
181
|
'{userId}' => user_id,
|
248
|
-
'{campaignKey}' => winner_campaign[
|
249
|
-
'{groupName}' => group_name
|
182
|
+
'{campaignKey}' => winner_campaign['key'],
|
183
|
+
'{groupName}' => group_name
|
250
184
|
}
|
251
185
|
)
|
252
186
|
|
253
|
-
if
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
end
|
260
|
-
else
|
261
|
-
@logger.log(
|
262
|
-
LogLevelEnum::INFO,
|
263
|
-
'MEG_CALLED_CAMPAIGN_NOT_WINNER',
|
264
|
-
{
|
265
|
-
'{file}' => FILE,
|
266
|
-
'{campaignKey}' => campaign_key,
|
267
|
-
'{userId}' => user_id,
|
268
|
-
'{groupName}' => group_name,
|
269
|
-
}
|
270
|
-
)
|
271
|
-
return nil
|
272
|
-
end
|
187
|
+
return if meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign)
|
188
|
+
|
189
|
+
variation = get_variation_allotted(user_id, campaign, true)
|
190
|
+
return nil unless variation && variation['name']
|
191
|
+
|
192
|
+
save_user_storage(user_id, campaign_key, campaign['type'], variation['name'], goal_identifier, true) if variation['name']
|
273
193
|
end
|
274
194
|
end
|
275
195
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
@
|
285
|
-
|
196
|
+
variation ||= get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision)
|
197
|
+
return unless variation
|
198
|
+
|
199
|
+
variation
|
200
|
+
end
|
201
|
+
|
202
|
+
def campaign_not_activated?(user_id, campaign_key, api_name)
|
203
|
+
if ([ApiMethods::TRACK, ApiMethods::GET_VARIATION_NAME, ApiMethods::GET_FEATURE_VARIABLE_VALUE].include? api_name) && @user_storage_service
|
204
|
+
@logger.log(
|
205
|
+
LogLevelEnum::WARNING,
|
206
|
+
'CAMPAIGN_NOT_ACTIVATED',
|
207
|
+
{
|
208
|
+
'{file}' => FILE,
|
209
|
+
'{campaignKey}' => campaign_key,
|
210
|
+
'{userId}' => user_id,
|
211
|
+
'{api}' => api_name
|
212
|
+
}
|
213
|
+
)
|
214
|
+
|
215
|
+
@logger.log(
|
216
|
+
LogLevelEnum::INFO,
|
217
|
+
'CAMPAIGN_NOT_ACTIVATED',
|
218
|
+
{
|
219
|
+
'{file}' => FILE,
|
220
|
+
'{campaignKey}' => campaign_key,
|
221
|
+
'{userId}' => user_id,
|
222
|
+
'{reason}' => api_name == ApiMethods::TRACK ? 'track it' : 'get the decision/value'
|
223
|
+
}
|
224
|
+
)
|
225
|
+
return true
|
226
|
+
end
|
227
|
+
false
|
228
|
+
end
|
229
|
+
|
230
|
+
def meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign)
|
231
|
+
unless winner_campaign && winner_campaign['id'] == campaign['id']
|
232
|
+
@logger.log(
|
233
|
+
LogLevelEnum::INFO,
|
234
|
+
'MEG_CALLED_CAMPAIGN_NOT_WINNER',
|
235
|
+
{
|
236
|
+
'{file}' => FILE,
|
237
|
+
'{campaignKey}' => campaign['key'],
|
238
|
+
'{userId}' => user_id,
|
239
|
+
'{groupName}' => group_name
|
240
|
+
}
|
241
|
+
)
|
242
|
+
return true
|
286
243
|
end
|
244
|
+
false
|
245
|
+
end
|
287
246
|
|
288
|
-
|
247
|
+
# Intitialize decision properties for hook manager
|
248
|
+
#
|
249
|
+
# @param[String] :user_id The unique ID assigned to User
|
250
|
+
# @param[Hash] :campaign Campaign hash itself
|
251
|
+
# @param[String] :api_name Name of the current api call
|
252
|
+
# @param[String] :goal_identifier The unique campaign's goal identifier
|
253
|
+
# @param[Hash] :custom_variables Key/value pair for segmentation
|
254
|
+
# @param[Hash] :variation_targeting_variables Key/value pair for whitelisting
|
255
|
+
# @return[Hash] Decision properties for the callback by hook manager
|
256
|
+
def initialize_decision_properties(user_id, campaign, api_name, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '')
|
257
|
+
{
|
258
|
+
campaign_id: campaign['id'],
|
259
|
+
campaign_key: campaign['key'],
|
260
|
+
campaign_type: campaign['type'],
|
261
|
+
# campaign segmentation conditions
|
262
|
+
custom_variables: custom_variables,
|
263
|
+
# event name
|
264
|
+
event: Hooks::DECISION_TYPES['CAMPAIGN_DECISION'],
|
265
|
+
# goal tracked in case of track API
|
266
|
+
goal_identifier: goal_identifier,
|
267
|
+
# campaign whitelisting flag
|
268
|
+
is_forced_variation_enabled: campaign['isForcedVariationEnabled'] || false,
|
269
|
+
sdk_version: SDK_VERSION,
|
270
|
+
# API name which triggered the event
|
271
|
+
source: api_name,
|
272
|
+
# Passed in API
|
273
|
+
user_id: user_id,
|
274
|
+
# Campaign Whitelisting conditions
|
275
|
+
variation_targeting_variables: variation_targeting_variables,
|
276
|
+
is_user_whitelisted: false,
|
277
|
+
from_user_storage_service: false,
|
278
|
+
# VWO generated UUID based on passed UserId and Account ID
|
279
|
+
vwo_user_id: generator_for(user_id, @settings_file['accountId'])
|
280
|
+
}
|
281
|
+
end
|
282
|
+
|
283
|
+
# Add variation details to decision properties for hook manager
|
284
|
+
#
|
285
|
+
# @param[Hash] :campaign Campaign details
|
286
|
+
# @param[Hash] :variation Variation assigned to user
|
287
|
+
# @param[Hash] :decision Decision properties
|
288
|
+
# @return[Hash] :decision Decision properties
|
289
|
+
def add_variation_to_decision_properties(decision, campaign, variation)
|
290
|
+
if campaign['type'] == CampaignTypes::VISUAL_AB || campaign['type'] == CampaignTypes::FEATURE_TEST
|
291
|
+
decision[:variation_name] = variation['name']
|
292
|
+
decision[:variation_id] = variation['id']
|
293
|
+
end
|
294
|
+
decision[:is_feature_enabled] = variation['isFeatureEnabled'] if campaign['type'] == CampaignTypes::FEATURE_TEST
|
295
|
+
decision
|
289
296
|
end
|
290
297
|
|
291
298
|
# Get variation by murmur logic if pre segmentation pass
|
@@ -297,10 +304,9 @@ class VWO
|
|
297
304
|
# @param[Hash] :decision data containing campaign info passed to hooks manager
|
298
305
|
#
|
299
306
|
# @return[Hash]
|
300
|
-
def
|
301
|
-
unless is_presegmentation
|
302
|
-
|
303
|
-
end
|
307
|
+
def get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision)
|
308
|
+
return nil unless is_presegmentation
|
309
|
+
|
304
310
|
campaign_key = campaign['key']
|
305
311
|
variation = get_variation_allotted(user_id, campaign)
|
306
312
|
if variation && variation['name']
|
@@ -318,13 +324,7 @@ class VWO
|
|
318
324
|
end
|
319
325
|
|
320
326
|
if variation
|
321
|
-
|
322
|
-
decision[:variation_name] = variation['name']
|
323
|
-
decision[:variation_id] = variation['id']
|
324
|
-
if campaign['type'] == CampaignTypes::FEATURE_TEST
|
325
|
-
decision[:is_feature_enabled] = variation['isFeatureEnabled']
|
326
|
-
end
|
327
|
-
end
|
327
|
+
decision = add_variation_to_decision_properties(decision, campaign, variation)
|
328
328
|
@hooks_manager.execute(decision)
|
329
329
|
end
|
330
330
|
variation
|
@@ -352,8 +352,8 @@ class VWO
|
|
352
352
|
end
|
353
353
|
|
354
354
|
if @bucketer.user_part_of_campaign?(user_id, campaign, true)
|
355
|
-
|
356
|
-
|
355
|
+
get_variation_of_campaign_for_user(user_id, campaign, disable_logs)
|
356
|
+
|
357
357
|
else
|
358
358
|
# not part of campaign
|
359
359
|
@logger.log(
|
@@ -385,7 +385,7 @@ class VWO
|
|
385
385
|
'USER_VARIATION_ALLOCATION_STATUS',
|
386
386
|
{
|
387
387
|
'{file}' => FILE,
|
388
|
-
'{status}' => variation ?
|
388
|
+
'{status}' => variation ? "got variation: + #{variation['name']}" : 'did not get any variation',
|
389
389
|
'{userId}' => user_id,
|
390
390
|
'{campaignKey}' => campaign['key']
|
391
391
|
},
|
@@ -418,12 +418,12 @@ class VWO
|
|
418
418
|
# @param[Boolean] :disable_logs optional: disable logs if True
|
419
419
|
# @return[Boolean] true if found otherwise false
|
420
420
|
|
421
|
-
def save_user_storage(user_id, campaign_key,
|
421
|
+
def save_user_storage(user_id, campaign_key, _campaign_type, variation_name, goal_identifier, disable_logs = false)
|
422
422
|
unless @user_storage_service
|
423
423
|
@logger.log(
|
424
424
|
LogLevelEnum::DEBUG,
|
425
425
|
'USER_STORAGE_SERVICE_NOT_CONFIGURED',
|
426
|
-
{'{file}' => FILE},
|
426
|
+
{ '{file}' => FILE },
|
427
427
|
disable_logs
|
428
428
|
)
|
429
429
|
return false
|
@@ -432,9 +432,7 @@ class VWO
|
|
432
432
|
new_campaign_user_mapping['campaign_key'] = campaign_key
|
433
433
|
new_campaign_user_mapping['user_id'] = user_id
|
434
434
|
new_campaign_user_mapping['variation_name'] = variation_name
|
435
|
-
|
436
|
-
new_campaign_user_mapping['goal_identifier'] = goal_identifier
|
437
|
-
end
|
435
|
+
new_campaign_user_mapping['goal_identifier'] = goal_identifier unless goal_identifier.empty?
|
438
436
|
|
439
437
|
@user_storage_service.set(new_campaign_user_mapping)
|
440
438
|
|
@@ -463,6 +461,12 @@ class VWO
|
|
463
461
|
false
|
464
462
|
end
|
465
463
|
|
464
|
+
def update_goal_identifier(user_id, campaign, variation, goal_identifier)
|
465
|
+
updated_goal_identifier = variation['goal_identifier']
|
466
|
+
updated_goal_identifier += VWO_DELIMITER + goal_identifier
|
467
|
+
save_user_storage(user_id, campaign['key'], campaign['name'], variation['name'], updated_goal_identifier) if variation['name']
|
468
|
+
end
|
469
|
+
|
466
470
|
private
|
467
471
|
|
468
472
|
# Evaluate all the variations in the campaign to find
|
@@ -476,20 +480,18 @@ class VWO
|
|
476
480
|
#
|
477
481
|
# @return[Hash]
|
478
482
|
|
479
|
-
def evaluate_whitelisting(user_id, campaign,
|
480
|
-
if campaign.key?('isUserListEnabled') && campaign[
|
483
|
+
def evaluate_whitelisting(user_id, campaign, _api_name, campaign_key, variation_targeting_variables = {}, disable_logs = false)
|
484
|
+
if campaign.key?('isUserListEnabled') && campaign['isUserListEnabled']
|
481
485
|
vwo_user_id = generator_for(user_id, @settings_file['accountId'], true)
|
482
486
|
if variation_targeting_variables.nil?
|
483
487
|
variation_targeting_variables = { _vwo_user_id: vwo_user_id }
|
484
488
|
else
|
485
489
|
variation_targeting_variables[:_vwo_user_id] = vwo_user_id
|
486
490
|
end
|
491
|
+
elsif variation_targeting_variables.nil?
|
492
|
+
variation_targeting_variables = { _vwo_user_id: user_id }
|
487
493
|
else
|
488
|
-
|
489
|
-
variation_targeting_variables = { _vwo_user_id: user_id }
|
490
|
-
else
|
491
|
-
variation_targeting_variables[:_vwo_user_id] = user_id
|
492
|
-
end
|
494
|
+
variation_targeting_variables[:_vwo_user_id] = user_id
|
493
495
|
end
|
494
496
|
targeted_variations = []
|
495
497
|
|
@@ -513,7 +515,11 @@ class VWO
|
|
513
515
|
'{customVariables}' => variation_targeting_variables,
|
514
516
|
'{status}' => status,
|
515
517
|
'{segmentationType}' => SegmentationTypeEnum::WHITELISTING,
|
516
|
-
'{variation}' => status == StatusEnum::PASSED
|
518
|
+
'{variation}' => if status == StatusEnum::PASSED
|
519
|
+
campaign['type'] == CampaignTypes::FEATURE_ROLLOUT ? 'and hence becomes part of the rollout' : "#{variation['name']} and hence becomes part of the rollout"
|
520
|
+
else
|
521
|
+
''
|
522
|
+
end
|
517
523
|
},
|
518
524
|
disable_logs
|
519
525
|
)
|
@@ -525,7 +531,7 @@ class VWO
|
|
525
531
|
'{file}' => FILE,
|
526
532
|
'{campaignKey}' => campaign_key,
|
527
533
|
'{userId}' => user_id,
|
528
|
-
'{variation}' => campaign['type'] == CampaignTypes::FEATURE_ROLLOUT ? '' :
|
534
|
+
'{variation}' => campaign['type'] == CampaignTypes::FEATURE_ROLLOUT ? '' : "for variation:#{variation['name']}"
|
529
535
|
},
|
530
536
|
disable_logs
|
531
537
|
)
|
@@ -582,7 +588,7 @@ class VWO
|
|
582
588
|
end
|
583
589
|
|
584
590
|
def scale_campaigns_weight(campaigns)
|
585
|
-
normalize_weight = 100/campaigns.length
|
591
|
+
normalize_weight = 100 / campaigns.length
|
586
592
|
campaigns.each do |campaign|
|
587
593
|
campaign['weight'] = normalize_weight
|
588
594
|
end
|
@@ -600,7 +606,7 @@ class VWO
|
|
600
606
|
@logger.log(
|
601
607
|
LogLevelEnum::DEBUG,
|
602
608
|
'USER_STORAGE_SERVICE_NOT_CONFIGURED',
|
603
|
-
{'{file}' => FILE},
|
609
|
+
{ '{file}' => FILE },
|
604
610
|
disable_logs
|
605
611
|
)
|
606
612
|
return false
|
@@ -643,7 +649,7 @@ class VWO
|
|
643
649
|
#
|
644
650
|
# @return[Object, nil] if found then variation settings object otherwise None
|
645
651
|
|
646
|
-
def get_stored_variation(
|
652
|
+
def get_stored_variation(_user_id, campaign_key, user_campaign_map, _disable_logs = false)
|
647
653
|
return unless user_campaign_map['campaign_key'] == campaign_key
|
648
654
|
|
649
655
|
variation_name = user_campaign_map['variation_name']
|
@@ -664,15 +670,13 @@ class VWO
|
|
664
670
|
# @param[Boolean] :disable_logs optional: disable logs if True
|
665
671
|
#
|
666
672
|
# @return[Boolean]
|
667
|
-
def
|
673
|
+
def presegmentation?(campaign, user_id, custom_variables, _api_name, disable_logs = false)
|
668
674
|
campaign_key = campaign['key']
|
669
675
|
segments = get_segments(campaign)
|
670
676
|
is_valid_segments = valid_value?(segments)
|
671
677
|
|
672
678
|
if is_valid_segments
|
673
|
-
|
674
|
-
custom_variables = {}
|
675
|
-
end
|
679
|
+
custom_variables ||= {}
|
676
680
|
response = @segment_evaluator.evaluate(campaign_key, user_id, segments, custom_variables, disable_logs)
|
677
681
|
@logger.log(
|
678
682
|
LogLevelEnum::INFO,
|
@@ -732,11 +736,11 @@ class VWO
|
|
732
736
|
eligible_campaigns = []
|
733
737
|
|
734
738
|
group_campaigns.each do |campaign|
|
735
|
-
if called_campaign[
|
739
|
+
if called_campaign['id'] == campaign['id'] || presegmentation?(campaign, user_id, custom_variables, '', true) && @bucketer.user_part_of_campaign?(user_id, campaign, true)
|
736
740
|
eligible_campaigns.push(campaign)
|
737
741
|
end
|
738
742
|
end
|
739
|
-
|
743
|
+
eligible_campaigns
|
740
744
|
end
|
741
745
|
|
742
746
|
# Finds and returns the winner campaign from eligible_campaigns list.
|
@@ -746,14 +750,12 @@ class VWO
|
|
746
750
|
#
|
747
751
|
# @return[Hash]
|
748
752
|
def get_winner_campaign(user_id, eligible_campaigns, group_id)
|
749
|
-
if eligible_campaigns.length == 1
|
750
|
-
return eligible_campaigns[0]
|
751
|
-
end
|
753
|
+
return eligible_campaigns[0] if eligible_campaigns.length == 1
|
752
754
|
|
753
755
|
eligible_campaigns = scale_campaigns_weight(eligible_campaigns)
|
754
756
|
eligible_campaigns = set_campaign_allocation(eligible_campaigns)
|
755
757
|
bucket_value = @bucketer.get_bucket_value_for_user(user_id, {}, group_id, true)
|
756
|
-
|
758
|
+
@bucketer.get_campaign_using_range(bucket_value, eligible_campaigns)
|
757
759
|
end
|
758
760
|
|
759
761
|
# Get campaign keys of all eligible Campaigns.
|
@@ -764,7 +766,7 @@ class VWO
|
|
764
766
|
def get_eligible_campaigns_key(eligible_campaigns)
|
765
767
|
eligible_campaigns_key = []
|
766
768
|
eligible_campaigns.each do |campaign|
|
767
|
-
eligible_campaigns_key.push(campaign[
|
769
|
+
eligible_campaigns_key.push(campaign['key'])
|
768
770
|
end
|
769
771
|
eligible_campaigns_key
|
770
772
|
end
|
@@ -778,9 +780,7 @@ class VWO
|
|
778
780
|
def get_non_eligible_campaigns_key(eligible_campaigns, group_campaigns)
|
779
781
|
non_eligible_campaigns_key = []
|
780
782
|
group_campaigns.each do |campaign|
|
781
|
-
unless eligible_campaigns.include? campaign
|
782
|
-
non_eligible_campaigns_key.push(campaign["key"])
|
783
|
-
end
|
783
|
+
non_eligible_campaigns_key.push(campaign['key']) unless eligible_campaigns.include? campaign
|
784
784
|
end
|
785
785
|
non_eligible_campaigns_key
|
786
786
|
end
|
@@ -795,54 +795,54 @@ class VWO
|
|
795
795
|
# @param[Boolean] :disable_logs optional: disable logs if True
|
796
796
|
# @return[Boolean]
|
797
797
|
|
798
|
-
def
|
798
|
+
def whitelisting_or_storage_for_grouped_campaigns?(user_id, called_campaign, group_campaigns, group_name, variation_targeting_variables, disable_logs = false)
|
799
799
|
group_campaigns.each do |campaign|
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
800
|
+
next unless called_campaign['id'] != campaign['id']
|
801
|
+
|
802
|
+
targeted_variation = evaluate_whitelisting(
|
803
|
+
user_id,
|
804
|
+
campaign,
|
805
|
+
'',
|
806
|
+
campaign['key'],
|
807
|
+
variation_targeting_variables,
|
808
|
+
true
|
809
|
+
)
|
810
|
+
next unless targeted_variation
|
811
|
+
|
812
|
+
@logger.log(
|
813
|
+
LogLevelEnum::INFO,
|
814
|
+
'OTHER_CAMPAIGN_SATISFIES_WHITELISTING_STORAGE',
|
815
|
+
{
|
816
|
+
'{file}' => FILE,
|
817
|
+
'{campaignKey}' => campaign['key'],
|
818
|
+
'{userId}' => user_id,
|
819
|
+
'{groupName}' => group_name,
|
820
|
+
'{type}' => 'whitelisting'
|
821
|
+
},
|
822
|
+
disable_logs
|
823
|
+
)
|
824
|
+
return true
|
825
825
|
end
|
826
826
|
|
827
827
|
group_campaigns.each do |campaign|
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
828
|
+
next unless called_campaign['id'] != campaign['id']
|
829
|
+
|
830
|
+
user_storage_data = get_user_storage(user_id, campaign['key'], true)
|
831
|
+
next unless user_storage_data
|
832
|
+
|
833
|
+
@logger.log(
|
834
|
+
LogLevelEnum::INFO,
|
835
|
+
'OTHER_CAMPAIGN_SATISFIES_WHITELISTING_STORAGE',
|
836
|
+
{
|
837
|
+
'{file}' => FILE,
|
838
|
+
'{campaignKey}' => campaign['key'],
|
839
|
+
'{userId}' => user_id,
|
840
|
+
'{groupName}' => group_name,
|
841
|
+
'{type}' => 'user storag'
|
842
|
+
},
|
843
|
+
disable_logs
|
844
|
+
)
|
845
|
+
return true
|
846
846
|
end
|
847
847
|
false
|
848
848
|
end
|
@@ -880,22 +880,16 @@ class VWO
|
|
880
880
|
'{file}' => FILE,
|
881
881
|
'{campaignKey}' => campaign_key,
|
882
882
|
'{userId}' => user_id,
|
883
|
-
'{customVariables}' => variation_targeting_variables
|
883
|
+
'{customVariables}' => variation_targeting_variables || {},
|
884
884
|
'{status}' => status,
|
885
885
|
'{segmentationType}' => SegmentationTypeEnum::WHITELISTING,
|
886
|
-
'{variation}' =>
|
886
|
+
'{variation}' => status == StatusEnum::PASSED && campaign['type'] != CampaignTypes::FEATURE_ROLLOUT ? "for variation:#{variation['name']}" : ' '
|
887
887
|
},
|
888
888
|
disable_logs
|
889
889
|
)
|
890
890
|
|
891
891
|
if variation
|
892
|
-
|
893
|
-
decision[:variation_name] = variation['name']
|
894
|
-
decision[:variation_id] = variation['id']
|
895
|
-
if campaign['type'] == CampaignTypes::FEATURE_TEST
|
896
|
-
decision[:is_feature_enabled] = variation['isFeatureEnabled']
|
897
|
-
end
|
898
|
-
end
|
892
|
+
decision = add_variation_to_decision_properties(decision, campaign, variation)
|
899
893
|
decision[:is_user_whitelisted] = true
|
900
894
|
@hooks_manager.execute(decision)
|
901
895
|
end
|
@@ -917,7 +911,6 @@ class VWO
|
|
917
911
|
end
|
918
912
|
nil
|
919
913
|
end
|
920
|
-
|
921
914
|
end
|
922
915
|
end
|
923
916
|
end
|