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 +4 -4
- data/lib/abc.txt +28 -0
- data/lib/vwo/constants.rb +5 -2
- data/lib/vwo/core/bucketer.rb +33 -5
- data/lib/vwo/core/variation_decider.rb +420 -131
- data/lib/vwo/enums.rb +6 -1
- data/lib/vwo/logger.rb +4 -2
- data/lib/vwo/schemas/settings_file.rb +32 -1
- data/lib/vwo/services/segment_evaluator.rb +4 -2
- data/lib/vwo/utils/campaign.rb +60 -2
- data/lib/vwo/utils/feature.rb +2 -0
- data/lib/vwo.rb +193 -193
- metadata +29 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84d01560f605a69e8ed011a19ba4e3aae0f67341fd653a562d817801d6a55073
|
4
|
+
data.tar.gz: b1355bef1b2b095774c702a6757c1a7141e2cf9758d0a1b8a0510111a8ee597a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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 = {
|
data/lib/vwo/core/bucketer.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
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
|
-
|
225
|
-
|
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::
|
226
|
+
LogMessageEnum::InfoMessages::GOT_ELIGIBLE_CAMPAIGNS,
|
233
227
|
file: FILE,
|
234
|
-
campaign_key: campaign_key,
|
235
228
|
user_id: user_id,
|
236
|
-
|
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
|
-
|
240
|
-
|
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::
|
246
|
-
file:
|
239
|
+
LogMessageEnum::InfoMessages::GOT_WINNER_CAMPAIGN,
|
240
|
+
file: FILE,
|
247
241
|
user_id: user_id,
|
248
|
-
campaign_key:
|
249
|
-
|
242
|
+
campaign_key: winner_campaign["key"],
|
243
|
+
group_name: group_name
|
250
244
|
)
|
251
245
|
)
|
252
|
-
|
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
|
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
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
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
|