vwo-sdk 1.35.0 → 1.38.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 +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
|