vwo-sdk 1.3.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2555f32eb2068e63dea737bdf3937708a5ef3e1e
4
- data.tar.gz: dd662a2ac80ba5dc6892375c15b3d13e2e0ed3a4
2
+ SHA256:
3
+ metadata.gz: 4e24789df43b6c0c71d71f8211c44ffe12c113e91943b91f8de581214353ccce
4
+ data.tar.gz: 95ec02ba3df3e88f91bf3f49eb5ab3ab64302b2c664d4d3caa6f569f2e618952
5
5
  SHA512:
6
- metadata.gz: 2dae59f19f9342856a343e5be3359b487069db19f4503398b577eed09c9e1e6ff98c37923c53b1fca91b5da5d66ad2d7a2414c582e0b02b3cb78f529a80a1568
7
- data.tar.gz: 1d1778ccde23e98efed73462dca543c84c12ccb2a7cf4cb18e129f63514268742afc4a0d7a394b16476dadef08eb2d0bbd47b312a13afce23f1c66c23f5a3a99
6
+ metadata.gz: 1dcc6b57a5fd35867d58d71f3f4b73b0da3ca73f01d009493f76b8981562e6d315f004a9095bcd20f230de1bf19559ac0a2ffefaa5befb72abae0e61de8fce6d
7
+ data.tar.gz: a7b154c4d9ae6c5b681c6cb27b231f3183a21c496e3eb5d33eecf81df0ca1d55922db127db37debe175aa060575f56dfe42ddbff29c0843e69839bcb57e4fc8c
data/lib/vwo.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Wingify Software Pvt. Ltd.
1
+ # Copyright 2019-2020 Wingify Software Pvt. Ltd.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # frozen_string_literal: true
15
+ require 'logger'
16
16
 
17
17
  require_relative 'vwo/services/settings_file_manager'
18
18
  require_relative 'vwo/services/event_dispatcher'
@@ -21,16 +21,19 @@ require_relative 'vwo/logger'
21
21
  require_relative 'vwo/enums'
22
22
  require_relative 'vwo/utils/campaign'
23
23
  require_relative 'vwo/utils/impression'
24
+ require_relative 'vwo/utils/feature'
25
+ require_relative 'vwo/utils/custom_dimensions'
24
26
  require_relative 'vwo/constants'
25
27
  require_relative 'vwo/core/variation_decider'
26
28
 
27
-
28
29
  # VWO main file
29
30
  class VWO
30
- attr_accessor :is_instance_valid
31
+ attr_accessor :is_instance_valid, :logger
31
32
 
32
33
  include Enums
33
34
  include Utils::Validations
35
+ include Utils::Feature
36
+ include Utils::CustomDimensions
34
37
  include Utils::Campaign
35
38
  include Utils::Impression
36
39
  include CONSTANTS
@@ -53,13 +56,15 @@ class VWO
53
56
  logger = nil,
54
57
  user_storage = nil,
55
58
  is_development_mode = false,
56
- settings_file = nil
59
+ settings_file = nil,
60
+ options = {}
57
61
  )
58
62
  @account_id = account_id
59
63
  @sdk_key = sdk_key
60
64
  @user_storage = user_storage
61
65
  @is_development_mode = is_development_mode
62
66
  @logger = VWO::Logger.get_instance(logger)
67
+ @logger.instance.level = options[:log_level] if (0..5).include?(options[:log_level])
63
68
 
64
69
  unless valid_settings_file?(get_settings(settings_file))
65
70
  @logger.log(
@@ -74,7 +79,10 @@ class VWO
74
79
 
75
80
  @logger.log(
76
81
  LogLevelEnum::DEBUG,
77
- format(LogMessageEnum::DebugMessages::VALID_CONFIGURATION, file: FILE)
82
+ format(
83
+ LogMessageEnum::DebugMessages::VALID_CONFIGURATION,
84
+ file: FILE
85
+ )
78
86
  )
79
87
 
80
88
  # Process the settings file
@@ -87,7 +95,10 @@ class VWO
87
95
  if is_development_mode
88
96
  @logger.log(
89
97
  LogLevelEnum::DEBUG,
90
- format(LogMessageEnum::DebugMessages::SET_DEVELOPMENT_MODE, file: FILE)
98
+ format(
99
+ LogMessageEnum::DebugMessages::SET_DEVELOPMENT_MODE,
100
+ file: FILE
101
+ )
91
102
  )
92
103
  end
93
104
  # Assign event dispatcher
@@ -96,7 +107,10 @@ class VWO
96
107
  # Successfully initialized VWO SDK
97
108
  @logger.log(
98
109
  LogLevelEnum::DEBUG,
99
- format(LogMessageEnum::DebugMessages::SDK_INITIALIZED, file: FILE)
110
+ format(
111
+ LogMessageEnum::DebugMessages::SDK_INITIALIZED,
112
+ file: FILE
113
+ )
100
114
  )
101
115
  end
102
116
 
@@ -122,15 +136,23 @@ class VWO
122
136
  #
123
137
  # @param[String] :campaign_key Unique campaign key
124
138
  # @param[String] :user_id ID assigned to a user
139
+ # @param[Hash] :options Options for custom variables required for segmentation
125
140
  # @return[String|None] If variation is assigned then variation-name
126
141
  # otherwise null in case of user not becoming part
127
142
 
128
- def activate(campaign_key, user_id)
143
+ def activate(campaign_key, user_id, options = {})
144
+ # Retrieve custom variables
145
+ custom_variables = options['custom_variables'] || options[:custom_variables]
146
+
129
147
  # Validate input parameters
130
- unless valid_string?(campaign_key) && valid_string?(user_id)
148
+ unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables))
131
149
  @logger.log(
132
150
  LogLevelEnum::ERROR,
133
- format(LogMessageEnum::ErrorMessages::ACTIVATE_API_MISSING_PARAMS, file: FILE)
151
+ format(
152
+ LogMessageEnum::ErrorMessages::ACTIVATE_API_MISSING_PARAMS,
153
+ api_name: ApiMethods::ACTIVATE,
154
+ file: FILE
155
+ )
134
156
  )
135
157
  return
136
158
  end
@@ -138,7 +160,11 @@ class VWO
138
160
  unless @is_instance_valid
139
161
  @logger.log(
140
162
  LogLevelEnum::ERROR,
141
- format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
163
+ format(
164
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
165
+ file: FILE,
166
+ api_name: ApiMethods::ACTIVATE
167
+ )
142
168
  )
143
169
  return
144
170
  end
@@ -151,23 +177,54 @@ class VWO
151
177
  # Log Campaign as invalid
152
178
  @logger.log(
153
179
  LogLevelEnum::ERROR,
154
- format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_key: campaign_key, api: 'activate')
180
+ format(
181
+ LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
182
+ file: FILE,
183
+ campaign_key: campaign_key,
184
+ api_name: ApiMethods::ACTIVATE
185
+ )
186
+ )
187
+ return
188
+ end
189
+
190
+ # Get campaign type
191
+ campaign_type = campaign['type']
192
+
193
+ # Validate valid api call
194
+ if campaign_type != CampaignTypes::VISUAL_AB
195
+ @logger.log(
196
+ LogLevelEnum::ERROR,
197
+ format(
198
+ LogMessageEnum::ErrorMessages::INVALID_API,
199
+ file: FILE,
200
+ api_name: ApiMethods::ACTIVATE,
201
+ user_id: user_id,
202
+ campaign_key: campaign_key,
203
+ campaign_type: campaign_type
204
+ )
155
205
  )
156
206
  return
157
207
  end
158
208
 
159
209
  # Once the matching RUNNING campaign is found, assign the
160
210
  # deterministic variation to the user_id provided
161
- variation_id, variation_name = @variation_decider.get_variation(
211
+ variation = @variation_decider.get_variation(
162
212
  user_id,
163
- campaign
213
+ campaign,
214
+ campaign_key,
215
+ custom_variables
164
216
  )
165
217
 
166
218
  # Check if variation_name has been assigned
167
- unless valid_value?(variation_name)
219
+ if variation.nil?
168
220
  @logger.log(
169
221
  LogLevelEnum::INFO,
170
- format(LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY, file: FILE, user_id: user_id, campaign_key: campaign_key)
222
+ format(
223
+ LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY,
224
+ file: FILE,
225
+ user_id: user_id,
226
+ campaign_key: campaign_key
227
+ )
171
228
  )
172
229
  return
173
230
  end
@@ -176,11 +233,22 @@ class VWO
176
233
  impression = create_impression(
177
234
  @settings_file,
178
235
  campaign['id'],
179
- variation_id,
236
+ variation['id'],
180
237
  user_id
181
238
  )
182
239
  @event_dispatcher.dispatch(impression)
183
- variation_name
240
+ variation['name']
241
+ rescue StandardError => e
242
+ @logger.log(
243
+ LogLevelEnum::ERROR,
244
+ format(
245
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
246
+ file: FILE,
247
+ api_name: ApiMethods::ACTIVATE,
248
+ exception: e
249
+ )
250
+ )
251
+ nil
184
252
  end
185
253
 
186
254
  # This API method: Gets the variation name assigned for the
@@ -195,25 +263,35 @@ class VWO
195
263
  #
196
264
  # @param[String] :campaign_key Unique campaign key
197
265
  # @param[String] :user_id ID assigned to a user
266
+ # @param[Hash] :options Options for custom variables required for segmentation
198
267
  #
199
268
  # @@return[String|Nil] If variation is assigned then variation-name
200
269
  # Otherwise null in case of user not becoming part
201
270
  #
202
- def get_variation_name(campaign_key, user_id)
203
- # Check for valid arguments
204
- unless valid_string?(campaign_key) && valid_string?(user_id)
205
- # log invalid params
271
+ def get_variation_name(campaign_key, user_id, options = {})
272
+ # Retrieve custom variables
273
+ custom_variables = options['custom_variables'] || options[:custom_variables]
274
+
275
+ # Validate input parameters
276
+ unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables))
206
277
  @logger.log(
207
278
  LogLevelEnum::ERROR,
208
- format(LogMessageEnum::ErrorMessages::GET_VARIATION_NAME_API_MISSING_PARAMS, file: FILE)
279
+ format(
280
+ LogMessageEnum::ErrorMessages::GET_VARIATION_NAME_API_INVALID_PARAMS,
281
+ api_name: ApiMethods::GET_VARIATION_NAME,
282
+ file: FILE
283
+ )
209
284
  )
210
285
  return
211
286
  end
212
-
213
287
  unless @is_instance_valid
214
288
  @logger.log(
215
289
  LogLevelEnum::ERROR,
216
- format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
290
+ format(
291
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
292
+ file: FILE,
293
+ api_name: ApiMethods::GET_VARIATION_NAME
294
+ )
217
295
  )
218
296
  return
219
297
  end
@@ -225,27 +303,62 @@ class VWO
225
303
  if campaign.nil? || campaign['status'] != STATUS_RUNNING
226
304
  @logger.log(
227
305
  LogLevelEnum::ERROR,
228
- format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_key: campaign_key, api: 'get_variation')
306
+ format(
307
+ LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
308
+ file: FILE,
309
+ campaign_key: campaign_key,
310
+ api_name: ApiMethods::GET_VARIATION_NAME
311
+ )
229
312
  )
230
313
  return
231
314
  end
232
315
 
233
- _variation_id, variation_name = @variation_decider.get_variation(
234
- user_id,
235
- campaign
236
- )
316
+ campaign_type = campaign['type']
317
+
318
+ if campaign_type == CampaignTypes::FEATURE_ROLLOUT
319
+ @logger.log(
320
+ LogLevelEnum::ERROR,
321
+ format(
322
+ LogMessageEnum::ErrorMessages.INVALID_API,
323
+ file: FILE,
324
+ api_name: ApiMethods::GET_VARIATION_NAME,
325
+ user_id: user_id,
326
+ campaign_key: campaign_key,
327
+ campaign_type: campaign_type
328
+ )
329
+ )
330
+ return
331
+ end
332
+
333
+ variation = @variation_decider.get_variation(user_id, campaign, campaign_key, custom_variables)
237
334
 
238
335
  # Check if variation_name has been assigned
239
- unless valid_value?(variation_name)
336
+ unless valid_value?(variation)
240
337
  # log invalid variation key
241
338
  @logger.log(
242
339
  LogLevelEnum::INFO,
243
- format(LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY, file: FILE, user_id: user_id, campaign_key: campaign_key)
340
+ format(
341
+ LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY,
342
+ file: FILE,
343
+ user_id: user_id,
344
+ campaign_key: campaign_key
345
+ )
244
346
  )
245
347
  return
246
348
  end
247
349
 
248
- variation_name
350
+ variation['name']
351
+ rescue StandardError => e
352
+ @logger.log(
353
+ LogLevelEnum::ERROR,
354
+ format(
355
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
356
+ file: FILE,
357
+ api_name: ApiMethods::GET_VARIATION_NAME,
358
+ exception: e
359
+ )
360
+ )
361
+ nil
249
362
  end
250
363
 
251
364
  # This API method: Marks the conversion of the campaign
@@ -258,22 +371,30 @@ class VWO
258
371
  #
259
372
  # @param[String] :campaign_key Unique campaign key
260
373
  # @param[String] :user_id ID assigned to a user
261
- # @param[String] :goal_identifier Unique campaign's goal identifier
262
- # @param[Numeric|String] :revenue_value Revenue value for revenue-type goal
374
+ # @param[String] :goal_identifier Unique campaign's goal identifier
375
+ # @param[Array|Hash] :args Contains revenue value and custom variables
376
+ # @param[Numeric|String] :revenue_value It is the revenue generated on triggering the goal
263
377
  #
264
378
  def track(campaign_key, user_id, goal_identifier, *args)
265
379
  if args[0].is_a?(Hash)
266
- revenue_value = args[0]['revenue_value']
380
+ revenue_value = args[0]['revenue_value'] || args[0][:revenue_value]
381
+ custom_variables = args[0]['custom_variables'] || args[0][:custom_variables]
267
382
  elsif args.is_a?(Array)
268
383
  revenue_value = args[0]
384
+ custom_variables = nil
269
385
  end
270
386
 
271
387
  # Check for valid args
272
- unless valid_string?(campaign_key) && valid_string?(user_id) && valid_string?(goal_identifier)
388
+ unless valid_string?(campaign_key) && valid_string?(user_id) && valid_string?(goal_identifier) &&
389
+ (custom_variables.nil? || valid_hash?(custom_variables)) || (revenue_value.nil? || valid_basic_data_type?(revenue_value))
273
390
  # log invalid params
274
391
  @logger.log(
275
392
  LogLevelEnum::ERROR,
276
- format(LogMessageEnum::ErrorMessages::TRACK_API_MISSING_PARAMS, file: FILE)
393
+ format(
394
+ LogMessageEnum::ErrorMessages::TRACK_API_INVALID_PARAMS,
395
+ file: FILE,
396
+ api_name: ApiMethods.TRACK
397
+ )
277
398
  )
278
399
  return false
279
400
  end
@@ -281,7 +402,11 @@ class VWO
281
402
  unless @is_instance_valid
282
403
  @logger.log(
283
404
  LogLevelEnum::ERROR,
284
- format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
405
+ format(
406
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
407
+ file: FILE,
408
+ api_name: ApiMethods::TRACK
409
+ )
285
410
  )
286
411
  return false
287
412
  end
@@ -290,33 +415,55 @@ class VWO
290
415
  campaign = get_campaign(@settings_file, campaign_key)
291
416
 
292
417
  # Validate campaign
293
- if campaign.nil? || campaign['status'] != STATUS_RUNNING
418
+ if campaign.nil? || (campaign['status'] != STATUS_RUNNING)
294
419
  # log error
295
420
  @logger.log(
296
421
  LogLevelEnum::ERROR,
297
- format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_key: campaign_key, api: 'track')
422
+ format(
423
+ LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
424
+ file: FILE,
425
+ campaign_key: campaign_key,
426
+ api_name: ApiMethods::TRACK
427
+ )
298
428
  )
299
429
  return false
300
430
  end
301
431
 
302
- campaign_id = campaign['id']
303
- variation_id, variation_name = @variation_decider.get_variation_allotted(user_id, campaign)
432
+ campaign_type = campaign['type']
304
433
 
305
- if variation_name
306
- goal = get_campaign_goal(@settings_file, campaign['key'], goal_identifier)
434
+ if campaign_type == CampaignTypes::FEATURE_ROLLOUT
435
+ @logger.log(
436
+ LogLevelEnum::ERROR,
437
+ format(
438
+ LogMessageEnum::ErrorMessages::INVALID_API,
439
+ file: FILE,
440
+ api_name: ApiMethods::TRACK,
441
+ user_id: user_id,
442
+ campaign_key: campaign_key,
443
+ campaign_type: campaign_type
444
+ )
445
+ )
446
+ return false
447
+ end
307
448
 
449
+ variation = @variation_decider.get_variation(user_id, campaign, campaign_key, custom_variables)
450
+
451
+ if variation
452
+ goal = get_campaign_goal(campaign, goal_identifier)
308
453
  if goal.nil?
309
454
  @logger.log(
310
455
  LogLevelEnum::ERROR,
311
456
  format(
312
457
  LogMessageEnum::ErrorMessages::TRACK_API_GOAL_NOT_FOUND,
313
- file: FILE, goal_identifier: goal_identifier,
458
+ file: FILE,
459
+ goal_identifier: goal_identifier,
314
460
  user_id: user_id,
315
- campaign_key: campaign_key
461
+ campaign_key: campaign_key,
462
+ api_name: ApiMethods::TRACK
316
463
  )
317
464
  )
318
465
  return false
319
- elsif goal['type'] == GOALTYPES::REVENUE && !valid_value?(revenue_value)
466
+ elsif goal['type'] == GoalTypes::REVENUE && !valid_value?(revenue_value)
320
467
  @logger.log(
321
468
  LogLevelEnum::ERROR,
322
469
  format(
@@ -324,25 +471,433 @@ class VWO
324
471
  file: FILE,
325
472
  user_id: user_id,
326
473
  goal_identifier: goal_identifier,
327
- campaign_key: campaign_key
474
+ campaign_key: campaign_key,
475
+ api_name: ApiMethods::TRACK
328
476
  )
329
477
  )
330
478
  return false
479
+ elsif goal['type'] == GoalTypes::CUSTOM
480
+ revenue_value = nil
331
481
  end
332
-
333
- revenue_value = nil if goal['type'] == GOALTYPES::CUSTOM
334
-
335
482
  impression = create_impression(
336
483
  @settings_file,
337
- campaign_id,
338
- variation_id,
484
+ campaign['id'],
485
+ variation['id'],
339
486
  user_id,
340
487
  goal['id'],
341
488
  revenue_value
342
489
  )
343
490
  @event_dispatcher.dispatch(impression)
491
+
492
+ @logger.log(
493
+ LogLevelEnum::INFO,
494
+ format(
495
+ LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
496
+ file: FILE,
497
+ campaign_id: impression[:experiment_id],
498
+ user_id: impression[:uId],
499
+ account_id: impression[:account_id],
500
+ variation_id: impression[:combination]
501
+ )
502
+ )
344
503
  return true
345
504
  end
346
505
  false
506
+ rescue StandardError => e
507
+ @logger.log(
508
+ LogLevelEnum::ERROR,
509
+ format(
510
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
511
+ file: FILE,
512
+ api_name: ApiMethods::TRACK,
513
+ exception: e
514
+ )
515
+ )
516
+ false
517
+ end
518
+
519
+ # This API method: Identifies whether the user becomes a part of feature rollout/test or not.
520
+ # 1. Validates the arguments being passed
521
+ # 2. Checks if user is eligible to get bucketed into the feature test/rollout,
522
+ # 3. Assigns the deterministic variation to the user(based on userId),
523
+ # If user becomes part of feature test/rollout
524
+ # If UserStorage is used, it will look into it for the variation and if found, no further processing is done
525
+ #
526
+ # @param[String] :campaign_key Unique campaign key
527
+ # @param[String] :user_id ID assigned to a user
528
+ # @param[Hash] :custom_variables Pass it through options as custom_variables={}
529
+ #
530
+ # @return[Boolean] true if user becomes part of feature test/rollout, otherwise false.
531
+
532
+ def feature_enabled?(campaign_key, user_id, options = {})
533
+ # Retrieve custom variables
534
+ custom_variables = options['custom_variables'] || options[:custom_variables]
535
+
536
+ # Validate input parameters
537
+ unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables))
538
+ @logger.log(
539
+ LogLevelEnum::ERROR,
540
+ format(
541
+ LogMessageEnum::ErrorMessages::IS_FEATURE_ENABLED_API_INVALID_PARAMS,
542
+ api_name: ApiMethods::IS_FEATURE_ENABLED,
543
+ file: FILE
544
+ )
545
+ )
546
+ return false
547
+ end
548
+ unless @is_instance_valid
549
+ @logger.log(
550
+ LogLevelEnum::ERROR,
551
+ format(
552
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
553
+ file: FILE,
554
+ api_name: ApiMethods::IS_FEATURE_ENABLED
555
+ )
556
+ )
557
+ return false
558
+ end
559
+
560
+ # Get the campaign settings
561
+ campaign = get_campaign(@settings_file, campaign_key)
562
+
563
+ # Validate campaign
564
+ unless campaign && campaign['status'] == STATUS_RUNNING
565
+ # log error
566
+ @logger.log(
567
+ LogLevelEnum::ERROR,
568
+ format(
569
+ LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
570
+ file: FILE,
571
+ campaign_key: campaign_key,
572
+ api_name: ApiMethods::IS_FEATURE_ENABLED
573
+ )
574
+ )
575
+ return false
576
+ end
577
+
578
+ # Validate campaign_type
579
+ campaign_type = campaign['type']
580
+
581
+ if campaign_type == CampaignTypes::VISUAL_AB
582
+ @logger.log(
583
+ LogLevelEnum::ERROR,
584
+ format(
585
+ LogMessageEnum::ErrorMessages::INVALID_API,
586
+ file: FILE,
587
+ api_name: ApiMethods::IS_FEATURE_ENABLED,
588
+ user_id: user_id,
589
+ campaign_key: campaign_key,
590
+ campaign_type: campaign_type
591
+ )
592
+ )
593
+ return false
594
+ end
595
+
596
+ # Get variation
597
+ variation = @variation_decider.get_variation(user_id, campaign, campaign_key, custom_variables)
598
+
599
+ # If no variation, did not become part of feature_test/rollout
600
+ return false unless variation
601
+
602
+ # if campaign type is feature_test Send track call to server
603
+ if campaign_type == CampaignTypes::FEATURE_TEST
604
+ impression = create_impression(
605
+ @settings_file,
606
+ campaign['id'],
607
+ variation['id'],
608
+ user_id
609
+ )
610
+
611
+ @event_dispatcher.dispatch(impression)
612
+ @logger.log(
613
+ LogLevelEnum::INFO,
614
+ format(
615
+ LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
616
+ file: FILE,
617
+ campaign_id: impression[:experiment_id],
618
+ user_id: impression[:uId],
619
+ account_id: impression[:account_id],
620
+ variation_id: impression[:combination]
621
+ )
622
+ )
623
+ result = variation['isFeatureEnabled']
624
+ if result
625
+ @logger.log(
626
+ LogLevelEnum::INFO,
627
+ format(
628
+ LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
629
+ file: FILE,
630
+ user_id: user_id,
631
+ feature_key: campaign_key,
632
+ api_name: ApiMethods::IS_FEATURE_ENABLED
633
+ )
634
+ )
635
+ else
636
+ @logger.log(
637
+ LogLevelEnum::INFO,
638
+ format(
639
+ LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
640
+ file: FILE,
641
+ user_id: user_id,
642
+ feature_key: campaign_key,
643
+ api_name: ApiMethods::IS_FEATURE_ENABLED
644
+ )
645
+ )
646
+ end
647
+ return result
648
+ end
649
+ true
650
+ rescue StandardError => e
651
+ @logger.log(
652
+ LogLevelEnum::ERROR,
653
+ format(
654
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
655
+ file: FILE,
656
+ api_name: ApiMethods::IS_FEATURE_ENABLED,
657
+ exception: e
658
+ )
659
+ )
660
+ false
661
+ end
662
+
663
+ # Returns the feature variable corresponding to the variable_key
664
+ # passed. It typecasts the value to the corresponding value type
665
+ # found in settings_file
666
+ #
667
+ # 1. Validates the arguments being passed
668
+ # 2. Checks if user is eligible to get bucketed into the feature test/rollout,
669
+ # 3. Assigns the deterministic variation to the user(based on userId),
670
+ # If user becomes part of campaign
671
+ # If UserStorage is used, it will look into it for the variation and if found, no further processing is done
672
+ # 4. Retrieves the corresponding variable from variation assigned.
673
+ #
674
+ # @param[String] :campaign_key Unique campaign key
675
+ # @param[String] :variable_key Variable key
676
+ # @param[String] :user_id ID assigned to a user
677
+ # @param[Hash] :custom_variables Pass it through options as custom_variables={}
678
+ #
679
+ # @return[Boolean, String, Integer, Float, nil) If variation is assigned then variable corresponding to variation assigned else nil
680
+ #
681
+
682
+ def get_feature_variable_value(campaign_key, variable_key, user_id, options = {})
683
+ # Retrieve custom variables
684
+ custom_variables = options['custom_variables'] || options[:custom_variables]
685
+
686
+ unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
687
+ (custom_variables.nil? || valid_hash?(custom_variables))
688
+ @logger.log(
689
+ LogLevelEnum::ERROR,
690
+ format(
691
+ LogMessageEnum::ErrorMessages::GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS,
692
+ file: FILE,
693
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
694
+ )
695
+ )
696
+ return
697
+ end
698
+
699
+ unless @is_instance_valid
700
+ @logger.log(
701
+ LogLevelEnum::ERROR,
702
+ format(
703
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
704
+ file: FILE,
705
+ api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
706
+ )
707
+ )
708
+ return
709
+ end
710
+
711
+ # Get the campaign settings
712
+ campaign = get_campaign(@settings_file, campaign_key)
713
+
714
+ # Validate campaign
715
+ unless campaign && campaign['status'] == STATUS_RUNNING
716
+ # log error
717
+ @logger.log(
718
+ LogLevelEnum::ERROR,
719
+ format(
720
+ LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING,
721
+ file: FILE,
722
+ campaign_key: campaign_key,
723
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
724
+ )
725
+ )
726
+ return
727
+ end
728
+
729
+ campaign_type = campaign['type']
730
+
731
+ if campaign_type == CampaignTypes::VISUAL_AB
732
+ @logger.log(
733
+ LogLevelEnum::ERROR,
734
+ format(
735
+ LogMessageEnum::ErrorMessages::INVALID_API,
736
+ file: FILE,
737
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE,
738
+ campaign_key: campaign_key,
739
+ campaign_type: campaign_type,
740
+ user_id: user_id
741
+ )
742
+ )
743
+ return
744
+ end
745
+
746
+ variation = @variation_decider.get_variation(user_id, campaign, campaign_key, custom_variables)
747
+
748
+ # Check if variation has been assigned to user
749
+ return unless variation
750
+
751
+ if campaign_type == CampaignTypes::FEATURE_ROLLOUT
752
+ variables = campaign['variables']
753
+ elsif campaign_type == CampaignTypes::FEATURE_TEST
754
+ if !variation['isFeatureEnabled']
755
+ @logger.log(
756
+ LogLevelEnum::INFO,
757
+ format(
758
+ LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
759
+ file: FILE,
760
+ feature_key: campaign_key,
761
+ user_id: user_id,
762
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
763
+ )
764
+ )
765
+ variation = get_control_variation(campaign)
766
+ else
767
+ @logger.log(
768
+ LogLevelEnum::INFO,
769
+ format(
770
+ LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
771
+ file: FILE,
772
+ feature_key: campaign_key,
773
+ user_id: user_id,
774
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
775
+ )
776
+ )
777
+ end
778
+ variables = variation['variables']
779
+ end
780
+ variable = get_variable(variables, variable_key)
781
+
782
+ unless variable
783
+ # Log variable not found
784
+ @logger.log(
785
+ LogLevelEnum::ERROR,
786
+ format(
787
+ LogMessageEnum::ErrorMessages::VARIABLE_NOT_FOUND,
788
+ file: FILE,
789
+ variable_key: variable_key,
790
+ campaign_key: campaign_key,
791
+ campaign_type: campaign_type,
792
+ user_id: user_id,
793
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
794
+ )
795
+ )
796
+ return
797
+ end
798
+
799
+ @logger.log(
800
+ LogLevelEnum::INFO,
801
+ format(
802
+ LogMessageEnum::InfoMessages::VARIABLE_FOUND,
803
+ file: FILE,
804
+ variable_key: variable_key,
805
+ variable_value: variable['value'],
806
+ campaign_key: campaign_key,
807
+ campaign_type: campaign_type,
808
+ user_id: user_id,
809
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
810
+ )
811
+ )
812
+ get_type_casted_feature_value(variable['value'], variable['type'])
813
+ rescue StandardError => e
814
+ @logger.log(
815
+ LogLevelEnum::ERROR,
816
+ format(
817
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
818
+ file: FILE,
819
+ api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE,
820
+ exception: e
821
+ )
822
+ )
823
+ nil
824
+ end
825
+
826
+ # This API method: Makes a call to our server to store the tag_values
827
+ # 1. Validates the arguments being passed
828
+ # 2. Send a call to our server
829
+ # @param[String] :tag_key key name of the tag
830
+ # @param[String] :tag_value Value of the tag
831
+ # @param[String] :user_id ID of the user for which value should be stored
832
+ # @return true if call is made successfully, else false
833
+
834
+ def push(tag_key, tag_value, user_id)
835
+ unless valid_string?(tag_key) && valid_string?(tag_value) && valid_string?(user_id)
836
+ @logger.log(
837
+ LogLevelEnum::ERROR,
838
+ format(
839
+ LogMessageEnum::ErrorMessages::PUSH_API_INVALID_PARAMS,
840
+ file: FILE,
841
+ api_name: ApiMethods::PUSH
842
+ )
843
+ )
844
+ return false
845
+ end
846
+
847
+ if tag_key.length > PushApi::TAG_KEY_LENGTH
848
+ @logger.log(
849
+ LogLevelEnum::ERROR,
850
+ format(
851
+ LogMessageEnum::ErrorMessages::TAG_KEY_LENGTH_EXCEEDED,
852
+ file: FILE,
853
+ user_id: user_id,
854
+ tag_key: tag_key,
855
+ api_name: ApiMethods::PUSH
856
+ )
857
+ )
858
+ return false
859
+ end
860
+
861
+ if tag_value.length > PushApi::TAG_VALUE_LENGTH
862
+ @logger.log(
863
+ LogLevelEnum::ERROR,
864
+ format(
865
+ LogMessageEnum::ErrorMessages::TAG_VALUE_LENGTH_EXCEEDED,
866
+ file: FILE,
867
+ user_id: user_id,
868
+ tag_value: tag_value,
869
+ api_name: ApiMethods::PUSH
870
+ )
871
+ )
872
+ return false
873
+ end
874
+
875
+ impression = get_url_params(@settings_file, tag_key, tag_value, user_id)
876
+
877
+ @event_dispatcher.dispatch(impression)
878
+
879
+ @logger.log(
880
+ LogLevelEnum::INFO,
881
+ format(
882
+ LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_PUSH_API,
883
+ file: FILE,
884
+ u: impression['u'],
885
+ user_id: impression['uId'],
886
+ account_id: impression['account_id'],
887
+ tags: impression['tags']
888
+ )
889
+ )
890
+ true
891
+ rescue StandardError => e
892
+ @logger.log(
893
+ LogLevelEnum::ERROR,
894
+ format(
895
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
896
+ file: FILE,
897
+ api_name: ApiMethods::PUSH,
898
+ exception: e
899
+ )
900
+ )
901
+ false
347
902
  end
348
903
  end