vwo-sdk 1.16.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 +4 -4
- data/lib/abc.txt +28 -0
- data/lib/vwo/constants.rb +2 -1
- data/lib/vwo/core/bucketer.rb +33 -5
- data/lib/vwo/core/variation_decider.rb +416 -130
- data/lib/vwo/enums.rb +6 -1
- data/lib/vwo/logger.rb +4 -2
- data/lib/vwo/schemas/settings_file.rb +1 -0
- data/lib/vwo/services/segment_evaluator.rb +4 -2
- data/lib/vwo/utils/campaign.rb +58 -0
- data/lib/vwo.rb +71 -67
- metadata +2 -1
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
|
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,62 +95,17 @@ 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
|
|
@@ -194,8 +151,7 @@ class VWO
|
|
194
151
|
)
|
195
152
|
)
|
196
153
|
|
197
|
-
if ([ApiMethods::TRACK, ApiMethods::GET_VARIATION_NAME, ApiMethods::GET_FEATURE_VARIABLE_VALUE].include? api_name) &&
|
198
|
-
@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
|
199
155
|
@logger.log(
|
200
156
|
LogLevelEnum::DEBUG,
|
201
157
|
format(
|
@@ -223,82 +179,106 @@ class VWO
|
|
223
179
|
end
|
224
180
|
|
225
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
|
226
187
|
|
227
|
-
|
228
|
-
|
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
|
+
)
|
229
222
|
|
230
|
-
if is_valid_segments
|
231
|
-
unless custom_variables
|
232
223
|
@logger.log(
|
233
224
|
LogLevelEnum::INFO,
|
234
225
|
format(
|
235
|
-
LogMessageEnum::InfoMessages::
|
226
|
+
LogMessageEnum::InfoMessages::GOT_ELIGIBLE_CAMPAIGNS,
|
236
227
|
file: FILE,
|
237
|
-
campaign_key: campaign_key,
|
238
228
|
user_id: user_id,
|
239
|
-
|
229
|
+
no_of_eligible_campaigns: eligible_campaigns.length,
|
230
|
+
no_of_group_campaigns: group_campaigns.length,
|
231
|
+
group_name: group_name
|
240
232
|
)
|
241
233
|
)
|
242
|
-
|
243
|
-
|
244
|
-
unless @segment_evaluator.evaluate(campaign_key, user_id, segments, custom_variables)
|
234
|
+
|
235
|
+
winner_campaign = get_winner_campaign(user_id, eligible_campaigns, group_id)
|
245
236
|
@logger.log(
|
246
237
|
LogLevelEnum::INFO,
|
247
238
|
format(
|
248
|
-
LogMessageEnum::InfoMessages::
|
249
|
-
file:
|
239
|
+
LogMessageEnum::InfoMessages::GOT_WINNER_CAMPAIGN,
|
240
|
+
file: FILE,
|
250
241
|
user_id: user_id,
|
251
|
-
campaign_key:
|
252
|
-
|
242
|
+
campaign_key: winner_campaign["key"],
|
243
|
+
group_name: group_name
|
253
244
|
)
|
254
245
|
)
|
255
|
-
|
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
|
256
267
|
end
|
257
|
-
@logger.log(
|
258
|
-
LogLevelEnum::INFO,
|
259
|
-
format(
|
260
|
-
LogMessageEnum::InfoMessages::USER_PASSED_SEGMENTATION,
|
261
|
-
file: FileNameEnum::SegmentEvaluator,
|
262
|
-
user_id: user_id,
|
263
|
-
campaign_key: campaign_key,
|
264
|
-
custom_variables: custom_variables
|
265
|
-
)
|
266
|
-
)
|
267
|
-
else
|
268
|
-
@logger.log(
|
269
|
-
LogLevelEnum::INFO,
|
270
|
-
format(
|
271
|
-
LogMessageEnum::InfoMessages::SKIPPING_SEGMENTATION,
|
272
|
-
file: FILE,
|
273
|
-
campaign_key: campaign_key,
|
274
|
-
user_id: user_id,
|
275
|
-
api_name: api_name,
|
276
|
-
variation: ''
|
277
|
-
)
|
278
|
-
)
|
279
268
|
end
|
280
269
|
|
281
|
-
variation
|
282
|
-
|
283
|
-
if variation && variation['name']
|
284
|
-
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)
|
285
272
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
campaign_key: campaign_key,
|
292
|
-
user_id: user_id,
|
293
|
-
variation_name: variation['name'],
|
294
|
-
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)
|
295
279
|
)
|
296
|
-
|
297
|
-
|
298
|
-
@logger.log(
|
299
|
-
LogLevelEnum::INFO,
|
300
|
-
format(LogMessageEnum::InfoMessages::NO_VARIATION_ALLOCATED, file: FILE, campaign_key: campaign_key, user_id: user_id)
|
301
|
-
)
|
280
|
+
end
|
281
|
+
|
302
282
|
end
|
303
283
|
|
304
284
|
if variation
|
@@ -321,7 +301,7 @@ class VWO
|
|
321
301
|
#
|
322
302
|
# @return[Hash]
|
323
303
|
|
324
|
-
def get_variation_allotted(user_id, campaign)
|
304
|
+
def get_variation_allotted(user_id, campaign, disable_logs = false)
|
325
305
|
unless valid_value?(user_id)
|
326
306
|
@logger.log(
|
327
307
|
LogLevelEnum::ERROR,
|
@@ -341,7 +321,8 @@ class VWO
|
|
341
321
|
user_id: user_id,
|
342
322
|
campaign_key: campaign['key'],
|
343
323
|
method: 'get_variation_allotted'
|
344
|
-
)
|
324
|
+
),
|
325
|
+
disable_logs
|
345
326
|
)
|
346
327
|
variation
|
347
328
|
else
|
@@ -354,7 +335,8 @@ class VWO
|
|
354
335
|
user_id: user_id,
|
355
336
|
campaign_key: nil,
|
356
337
|
method: 'get_variation_allotted'
|
357
|
-
)
|
338
|
+
),
|
339
|
+
disable_logs
|
358
340
|
)
|
359
341
|
nil
|
360
342
|
end
|
@@ -413,13 +395,15 @@ class VWO
|
|
413
395
|
# @param[String] :campaign_key Unique campaign identifier
|
414
396
|
# @param[String] :variation_name Variation identifier
|
415
397
|
# @param[String] :goal_identifier The unique campaign's goal identifier
|
398
|
+
# @param[Boolean] :disable_logs optional: disable logs if True
|
416
399
|
# @return[Boolean] true if found otherwise false
|
417
400
|
|
418
|
-
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)
|
419
402
|
unless @user_storage_service
|
420
403
|
@logger.log(
|
421
404
|
LogLevelEnum::DEBUG,
|
422
|
-
format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_SAVE, file: FILE)
|
405
|
+
format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_SAVE, file: FILE),
|
406
|
+
disable_logs
|
423
407
|
)
|
424
408
|
return false
|
425
409
|
end
|
@@ -435,13 +419,28 @@ class VWO
|
|
435
419
|
|
436
420
|
@logger.log(
|
437
421
|
LogLevelEnum::INFO,
|
438
|
-
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
|
439
437
|
)
|
440
438
|
true
|
441
439
|
rescue StandardError
|
442
440
|
@logger.log(
|
443
441
|
LogLevelEnum::ERROR,
|
444
|
-
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
|
445
444
|
)
|
446
445
|
false
|
447
446
|
end
|
@@ -455,10 +454,11 @@ class VWO
|
|
455
454
|
# @param[String] :api_name The key Passed to identify the calling API
|
456
455
|
# @param[String] :campaign_key Unique campaign key
|
457
456
|
# @param[Hash] :variation_targeting_variables Key/value pair of Whitelisting Custom Attributes
|
457
|
+
# @param[Boolean] :disable_logs optional: disable logs if True
|
458
458
|
#
|
459
459
|
# @return[Hash]
|
460
460
|
|
461
|
-
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)
|
462
462
|
if variation_targeting_variables.nil?
|
463
463
|
variation_targeting_variables = { '_vwo_user_id' => user_id }
|
464
464
|
else
|
@@ -470,7 +470,7 @@ class VWO
|
|
470
470
|
segments = get_segments(variation)
|
471
471
|
is_valid_segments = valid_value?(segments)
|
472
472
|
if is_valid_segments
|
473
|
-
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)
|
474
474
|
targeted_variations.push(variation)
|
475
475
|
status = StatusEnum::PASSED
|
476
476
|
else
|
@@ -488,7 +488,8 @@ class VWO
|
|
488
488
|
variation_name: variation['name'],
|
489
489
|
segmentation_type: SegmentationTypeEnum::WHITELISTING,
|
490
490
|
api_name: api_name
|
491
|
-
)
|
491
|
+
),
|
492
|
+
disable_logs
|
492
493
|
)
|
493
494
|
else
|
494
495
|
@logger.log(
|
@@ -500,7 +501,8 @@ class VWO
|
|
500
501
|
user_id: user_id,
|
501
502
|
api_name: api_name,
|
502
503
|
variation: variation['name']
|
503
|
-
)
|
504
|
+
),
|
505
|
+
disable_logs
|
504
506
|
)
|
505
507
|
end
|
506
508
|
end
|
@@ -525,7 +527,8 @@ class VWO
|
|
525
527
|
whitelisted_variation = @bucketer.get_variation(
|
526
528
|
targeted_variations_deep_clone,
|
527
529
|
@bucketer.get_bucket_value_for_user(
|
528
|
-
user_id
|
530
|
+
user_id,
|
531
|
+
campaign
|
529
532
|
)
|
530
533
|
)
|
531
534
|
else
|
@@ -553,18 +556,26 @@ class VWO
|
|
553
556
|
end
|
554
557
|
end
|
555
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
|
556
565
|
# Get the UserStorageData after looking up into get method
|
557
566
|
# Being provided via UserStorageService
|
558
567
|
#
|
559
568
|
# @param[String]: Unique user identifier
|
560
569
|
# @param[String]: Unique campaign key
|
570
|
+
# @param[Boolean] :disable_logs if True
|
561
571
|
# @return[Hash|Boolean]: user_storage data
|
562
572
|
|
563
|
-
def get_user_storage(user_id, campaign_key)
|
573
|
+
def get_user_storage(user_id, campaign_key, disable_logs = false)
|
564
574
|
unless @user_storage_service
|
565
575
|
@logger.log(
|
566
576
|
LogLevelEnum::DEBUG,
|
567
|
-
format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_LOOKUP, file: FILE)
|
577
|
+
format(LogMessageEnum::DebugMessages::NO_USER_STORAGE_SERVICE_LOOKUP, file: FILE),
|
578
|
+
disable_logs
|
568
579
|
)
|
569
580
|
return false
|
570
581
|
end
|
@@ -577,13 +588,15 @@ class VWO
|
|
577
588
|
file: FILE,
|
578
589
|
user_id: user_id,
|
579
590
|
status: data.nil? ? 'Not Found' : 'Found'
|
580
|
-
)
|
591
|
+
),
|
592
|
+
disable_logs
|
581
593
|
)
|
582
594
|
data
|
583
595
|
rescue StandardError
|
584
596
|
@logger.log(
|
585
597
|
LogLevelEnum::ERROR,
|
586
|
-
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
|
587
600
|
)
|
588
601
|
false
|
589
602
|
end
|
@@ -593,10 +606,11 @@ class VWO
|
|
593
606
|
# @param[String] :user_id
|
594
607
|
# @param[String] :campaign_key campaign identified
|
595
608
|
# @param[Hash] :user_campaign_map BucketMap consisting of stored user variation
|
609
|
+
# @param[Boolean] :disable_logs if True
|
596
610
|
#
|
597
611
|
# @return[Object, nil] if found then variation settings object otherwise None
|
598
612
|
|
599
|
-
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)
|
600
614
|
return unless user_campaign_map['campaign_key'] == campaign_key
|
601
615
|
|
602
616
|
variation_name = user_campaign_map['variation_name']
|
@@ -608,7 +622,8 @@ class VWO
|
|
608
622
|
campaign_key: campaign_key,
|
609
623
|
user_id: user_id,
|
610
624
|
variation_name: variation_name
|
611
|
-
)
|
625
|
+
),
|
626
|
+
disable_logs
|
612
627
|
)
|
613
628
|
|
614
629
|
get_campaign_variation(
|
@@ -617,6 +632,277 @@ class VWO
|
|
617
632
|
variation_name
|
618
633
|
)
|
619
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
|
+
|
620
906
|
end
|
621
907
|
end
|
622
908
|
end
|
data/lib/vwo/enums.rb
CHANGED
@@ -113,6 +113,7 @@ class VWO
|
|
113
113
|
BULK_NOT_PROCESSED = "(%<file>s): Batch events couldn't be received by VWO. Calling Flush Callback with error and data."
|
114
114
|
BEFORE_FLUSHING = '(%<file>s): Flushing events queue %<manually>s having %<length>s events %<timer>s queue summary: %<queue_metadata>s'
|
115
115
|
EVENT_BATCHING_INSUFFICIENT = '(%<file>s): %<key>s not provided, assigning default value'
|
116
|
+
GOT_ELIGIBLE_CAMPAIGNS = "(%<file>s): Campaigns:%<eligible_campaigns_key>s are eligible, %<ineligible_campaigns_log_text>s are ineligible from the Group:%<group_name>s for the User ID:%<user_id>s"
|
116
117
|
end
|
117
118
|
|
118
119
|
# Info Messages
|
@@ -152,9 +153,13 @@ class VWO
|
|
152
153
|
CAMPAIGN_NOT_ACTIVATED = '(%<file>s): Activate the campaign:%<campaign_key>s for User ID:%<user_id>s to %<reason>s.'
|
153
154
|
GOAL_ALREADY_TRACKED = '(%<file>s): Goal:%<goal_identifier>s of Campaign:%<campaign_key>s for User ID:%<user_id>s has already been tracked earlier. Skipping now'
|
154
155
|
USER_ALREADY_TRACKED = '(%<file>s): User ID:%<user_id>s for Campaign:%<campaign_key>s has already been tracked earlier for "%<api_name>s" API. Skipping now'
|
155
|
-
API_CALLED = '(%<file>s): API:
|
156
|
+
API_CALLED = '(%<file>s): API: %<api_name>s called for UserId:%<user_id>s'
|
156
157
|
BULK_IMPRESSION_SUCCESS = '(%<file>s): Impression event - %<end_point>s was successfully received by VWO having accountId:%<a>s'
|
157
158
|
AFTER_FLUSHING = '(%<file>s): Events queue having %<length>s events has been flushed %<manually>s queue summary: %<queue_metadata>s'
|
159
|
+
GOT_WINNER_CAMPAIGN = "(%<file>s): Campaign:%<campaign_key>s is selected from the mutually exclusive group:%<group_name>s for the User ID:%<user_id>s"
|
160
|
+
GOT_ELIGIBLE_CAMPAIGNS = "(%<file>s): Got %<no_of_eligible_campaigns>s eligible winners out of %<no_of_group_campaigns>s from the Group:%<group_name>s and for User ID:%<user_id>s"
|
161
|
+
CALLED_CAMPAIGN_NOT_WINNER = "(%<file>s): Campaign:%<campaign_key>s does not qualify from the mutually exclusive group:%<group_name>s for User ID:%<user_id>s"
|
162
|
+
OTHER_CAMPAIGN_SATISFIES_WHITELISTING_OR_STORAGE = "(%<file>s): Campaign:%<campaign_key>s of Group:%<group_name>s satisfies %<type>s for User ID:%<user_id>s"
|
158
163
|
end
|
159
164
|
|
160
165
|
# Warning Messages
|
data/lib/vwo/logger.rb
CHANGED
@@ -28,8 +28,10 @@ class VWO
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Override this method to handle logs in a custom manner
|
31
|
-
def log(level, message)
|
32
|
-
|
31
|
+
def log(level, message, disable_logs = false)
|
32
|
+
unless disable_logs
|
33
|
+
@@logger_instance.log(level, message)
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
37
|
def instance
|
@@ -63,10 +63,11 @@ class VWO
|
|
63
63
|
# @param[String] :user_id Unique user identifier
|
64
64
|
# @param[Hash] :dsl Segments provided in the settings_file
|
65
65
|
# @param[Hash] :custom_variables Custom variables provided in the apis
|
66
|
+
# @param[Boolean] :disable_logs disable logs if True
|
66
67
|
#
|
67
68
|
# @return[Boolean] true if user passed pre-segmentation, else false
|
68
69
|
#
|
69
|
-
def evaluate(campaign_key, user_id, dsl, custom_variables)
|
70
|
+
def evaluate(campaign_key, user_id, dsl, custom_variables, disable_logs = false)
|
70
71
|
result = evaluate_util(dsl, custom_variables) if valid_value?(dsl)
|
71
72
|
result
|
72
73
|
rescue StandardError => e
|
@@ -79,7 +80,8 @@ class VWO
|
|
79
80
|
campaign_key: campaign_key,
|
80
81
|
custom_variables: custom_variables,
|
81
82
|
error_message: e
|
82
|
-
)
|
83
|
+
),
|
84
|
+
disable_logs
|
83
85
|
)
|
84
86
|
false
|
85
87
|
end
|
data/lib/vwo/utils/campaign.rb
CHANGED
@@ -57,6 +57,26 @@ class VWO
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
# Sets campaign allocation range in the provided campaigns list
|
61
|
+
#
|
62
|
+
# @param [Array]: Array of Campaigns
|
63
|
+
def set_campaign_allocation(campaigns)
|
64
|
+
current_allocation = 0
|
65
|
+
campaigns.each do |campaign|
|
66
|
+
step_factor = get_variation_bucketing_range(campaign['weight'])
|
67
|
+
if step_factor > 0
|
68
|
+
start_range = current_allocation + 1
|
69
|
+
end_range = current_allocation + step_factor
|
70
|
+
campaign['min_range'] = start_range
|
71
|
+
campaign['max_range'] = end_range
|
72
|
+
current_allocation += step_factor
|
73
|
+
else
|
74
|
+
campaign['min_range'] = -1
|
75
|
+
campaign['max_range'] = -1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
60
80
|
# Returns goal from given campaign_key and gaol_identifier.
|
61
81
|
# @param[String] :campaign Campaign object
|
62
82
|
# @param[String] :goal_identifier Goal identifier
|
@@ -249,6 +269,44 @@ class VWO
|
|
249
269
|
return campaign
|
250
270
|
end
|
251
271
|
|
272
|
+
# Checks whether a campaign is part of a group.
|
273
|
+
#
|
274
|
+
# @param[Hash] :settings_file Settings file for the project
|
275
|
+
# @param[Integer] :campaign_id Id of campaign which is to be checked
|
276
|
+
# @return[Boolean]
|
277
|
+
def is_part_of_group(settings_file, campaign_id)
|
278
|
+
if settings_file["campaignGroups"] && (settings_file["campaignGroups"].has_key?(campaign_id.to_s))
|
279
|
+
return true
|
280
|
+
end
|
281
|
+
false
|
282
|
+
end
|
283
|
+
|
284
|
+
# Returns campaigns which are part of given group using group_id.
|
285
|
+
#
|
286
|
+
# @param[Hash] :settings_file Settings file for the project
|
287
|
+
# @param[Integer] :group_id id of group whose campaigns are to be return
|
288
|
+
# @return[Array]
|
289
|
+
def get_group_campaigns(settings_file, group_id)
|
290
|
+
group_campaign_ids = []
|
291
|
+
group_campaigns = []
|
292
|
+
groups = settings_file["groups"]
|
293
|
+
|
294
|
+
if groups && groups.has_key?(group_id.to_s)
|
295
|
+
group_campaign_ids = groups[group_id.to_s]["campaigns"]
|
296
|
+
end
|
297
|
+
|
298
|
+
if group_campaign_ids
|
299
|
+
group_campaign_ids.each do |campaign_id|
|
300
|
+
settings_file["campaigns"].each do |campaign|
|
301
|
+
if campaign["id"] == campaign_id && campaign["status"] == STATUS_RUNNING
|
302
|
+
group_campaigns.append(campaign)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
group_campaigns
|
308
|
+
end
|
309
|
+
|
252
310
|
end
|
253
311
|
end
|
254
312
|
end
|
data/lib/vwo.rb
CHANGED
@@ -413,7 +413,6 @@ class VWO
|
|
413
413
|
)
|
414
414
|
end
|
415
415
|
end
|
416
|
-
variation['name']
|
417
416
|
else
|
418
417
|
@logger.log(
|
419
418
|
LogLevelEnum::INFO,
|
@@ -425,8 +424,8 @@ class VWO
|
|
425
424
|
api_name: ApiMethods::ACTIVATE
|
426
425
|
)
|
427
426
|
)
|
428
|
-
nil
|
429
427
|
end
|
428
|
+
variation['name']
|
430
429
|
rescue StandardError => e
|
431
430
|
@logger.log(
|
432
431
|
LogLevelEnum::ERROR,
|
@@ -676,7 +675,7 @@ class VWO
|
|
676
675
|
if !identifiers.include? goal_identifier
|
677
676
|
updated_goal_identifier = variation['goal_identifier']
|
678
677
|
updated_goal_identifier += VWO_DELIMITER + goal_identifier
|
679
|
-
@variation_decider.save_user_storage(user_id, campaign['key'], variation['name'], updated_goal_identifier) if variation['name']
|
678
|
+
@variation_decider.save_user_storage(user_id, campaign['key'], campaign['name'], variation['name'], updated_goal_identifier) if variation['name']
|
680
679
|
# set variation at user storage
|
681
680
|
elsif !should_track_returning_user
|
682
681
|
@logger.log(
|
@@ -870,80 +869,85 @@ class VWO
|
|
870
869
|
return false unless variation
|
871
870
|
|
872
871
|
# if campaign type is feature_test Send track call to server
|
873
|
-
if campaign_type == CampaignTypes::FEATURE_TEST
|
874
|
-
if is_eligible_to_send_impression(should_track_returning_user)
|
875
|
-
if defined?(@batch_events)
|
876
|
-
impression = create_bulk_event_impression(
|
877
|
-
@settings_file,
|
878
|
-
campaign['id'],
|
879
|
-
variation['id'],
|
880
|
-
user_id
|
881
|
-
)
|
882
|
-
@batch_events_queue.enqueue(impression)
|
883
|
-
else
|
884
|
-
impression = create_impression(
|
885
|
-
@settings_file,
|
886
|
-
campaign['id'],
|
887
|
-
variation['id'],
|
888
|
-
user_id,
|
889
|
-
@sdk_key,
|
890
|
-
goal_id: nil,
|
891
|
-
revenue: nil,
|
892
|
-
usage_stats: @usage_stats.usage_stats
|
893
|
-
)
|
894
872
|
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
variation_id: impression[:combination]
|
905
|
-
)
|
906
|
-
)
|
907
|
-
end
|
908
|
-
result = variation['isFeatureEnabled']
|
909
|
-
if result
|
910
|
-
@logger.log(
|
911
|
-
LogLevelEnum::INFO,
|
912
|
-
format(
|
913
|
-
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
914
|
-
file: FILE,
|
915
|
-
user_id: user_id,
|
916
|
-
feature_key: campaign_key,
|
917
|
-
api_name: ApiMethods::IS_FEATURE_ENABLED
|
918
|
-
)
|
919
|
-
)
|
920
|
-
else
|
921
|
-
@logger.log(
|
922
|
-
LogLevelEnum::INFO,
|
923
|
-
format(
|
924
|
-
LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
|
925
|
-
file: FILE,
|
926
|
-
user_id: user_id,
|
927
|
-
feature_key: campaign_key,
|
928
|
-
api_name: ApiMethods::IS_FEATURE_ENABLED
|
929
|
-
)
|
930
|
-
)
|
931
|
-
end
|
932
|
-
return result
|
873
|
+
if is_eligible_to_send_impression(should_track_returning_user)
|
874
|
+
if defined?(@batch_events)
|
875
|
+
impression = create_bulk_event_impression(
|
876
|
+
@settings_file,
|
877
|
+
campaign['id'],
|
878
|
+
variation['id'],
|
879
|
+
user_id
|
880
|
+
)
|
881
|
+
@batch_events_queue.enqueue(impression)
|
933
882
|
else
|
883
|
+
impression = create_impression(
|
884
|
+
@settings_file,
|
885
|
+
campaign['id'],
|
886
|
+
variation['id'],
|
887
|
+
user_id,
|
888
|
+
@sdk_key,
|
889
|
+
nil,
|
890
|
+
nil,
|
891
|
+
usage_stats: @usage_stats.usage_stats
|
892
|
+
)
|
893
|
+
|
894
|
+
@event_dispatcher.dispatch(impression)
|
934
895
|
@logger.log(
|
935
896
|
LogLevelEnum::INFO,
|
936
897
|
format(
|
937
|
-
LogMessageEnum::InfoMessages::
|
898
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
|
938
899
|
file: FILE,
|
939
|
-
|
940
|
-
|
941
|
-
|
900
|
+
campaign_id: impression[:experiment_id],
|
901
|
+
sdk_key: @sdk_key,
|
902
|
+
account_id: impression[:account_id],
|
903
|
+
variation_id: impression[:combination]
|
942
904
|
)
|
943
905
|
)
|
944
906
|
end
|
907
|
+
|
908
|
+
else
|
909
|
+
@logger.log(
|
910
|
+
LogLevelEnum::INFO,
|
911
|
+
format(
|
912
|
+
LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
|
913
|
+
file: FILE,
|
914
|
+
user_id: user_id,
|
915
|
+
campaign_key: campaign_key,
|
916
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
917
|
+
)
|
918
|
+
)
|
945
919
|
end
|
946
|
-
|
920
|
+
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
921
|
+
result = true
|
922
|
+
else
|
923
|
+
result = variation['isFeatureEnabled']
|
924
|
+
end
|
925
|
+
|
926
|
+
if result
|
927
|
+
@logger.log(
|
928
|
+
LogLevelEnum::INFO,
|
929
|
+
format(
|
930
|
+
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
931
|
+
file: FILE,
|
932
|
+
user_id: user_id,
|
933
|
+
feature_key: campaign_key,
|
934
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
935
|
+
)
|
936
|
+
)
|
937
|
+
else
|
938
|
+
@logger.log(
|
939
|
+
LogLevelEnum::INFO,
|
940
|
+
format(
|
941
|
+
LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
|
942
|
+
file: FILE,
|
943
|
+
user_id: user_id,
|
944
|
+
feature_key: campaign_key,
|
945
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
946
|
+
)
|
947
|
+
)
|
948
|
+
end
|
949
|
+
|
950
|
+
result
|
947
951
|
rescue StandardError => e
|
948
952
|
@logger.log(
|
949
953
|
LogLevelEnum::ERROR,
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vwo-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- VWO
|
@@ -87,6 +87,7 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
+
- lib/abc.txt
|
90
91
|
- lib/vwo.rb
|
91
92
|
- lib/vwo/constants.rb
|
92
93
|
- lib/vwo/core/bucketer.rb
|