kameleoon-client-ruby 2.1.0 → 2.1.1

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/client.rb +79 -133
  3. data/lib/kameleoon/configuration/rule.rb +1 -1
  4. data/lib/kameleoon/data/browser.rb +33 -0
  5. data/lib/kameleoon/data/conversion.rb +26 -0
  6. data/lib/kameleoon/data/custom_data.rb +53 -0
  7. data/lib/kameleoon/data/data.rb +35 -0
  8. data/lib/kameleoon/data/device.rb +26 -0
  9. data/lib/kameleoon/data/page_view.rb +31 -0
  10. data/lib/kameleoon/data/user_agent.rb +14 -0
  11. data/lib/kameleoon/network/activity_event.rb +31 -0
  12. data/lib/kameleoon/network/experiment_event.rb +35 -0
  13. data/lib/kameleoon/network/uri_helper.rb +36 -0
  14. data/lib/kameleoon/network/url_provider.rb +71 -0
  15. data/lib/kameleoon/request.rb +5 -19
  16. data/lib/kameleoon/targeting/condition.rb +40 -11
  17. data/lib/kameleoon/targeting/condition_factory.rb +35 -12
  18. data/lib/kameleoon/targeting/conditions/browser_condition.rb +71 -0
  19. data/lib/kameleoon/targeting/conditions/conversion_condition.rb +21 -0
  20. data/lib/kameleoon/targeting/conditions/custom_datum.rb +60 -65
  21. data/lib/kameleoon/targeting/conditions/device_condition.rb +21 -0
  22. data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -12
  23. data/lib/kameleoon/targeting/conditions/page_title_condition.rb +21 -0
  24. data/lib/kameleoon/targeting/conditions/page_url_condition.rb +21 -0
  25. data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +65 -0
  26. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +40 -0
  27. data/lib/kameleoon/targeting/conditions/target_experiment.rb +4 -8
  28. data/lib/kameleoon/targeting/conditions/unknown_condition.rb +15 -0
  29. data/lib/kameleoon/targeting/conditions/visitor_code_condition.rb +16 -0
  30. data/lib/kameleoon/targeting/models.rb +0 -24
  31. data/lib/kameleoon/utils.rb +1 -1
  32. data/lib/kameleoon/version.rb +28 -1
  33. metadata +22 -3
  34. data/lib/kameleoon/data.rb +0 -175
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba4f943be2e686ba2cca810ef8f456622e25733eda03808c7b3d81e2d72b1ee3
4
- data.tar.gz: cef2edf8ef8e449f3150f73c5df9d76477342a52e49fbf90885b458fd6aa1b57
3
+ metadata.gz: 1aef3f7b97d4a32024bec989ed4356cc1d10425c16b419b55f524cf1abfd4f52
4
+ data.tar.gz: 5705b067a3effc12b7f38ccef23e01ee28e370b99a212fd371ce0c863184c3ec
5
5
  SHA512:
6
- metadata.gz: 5b4e8f09c36222e08e9b426e90db6fb05476aa0e9bcd53036de31a8d7819db7b95ea5960adc6cc059494eb5355d9d912dd73a507923904723cf9ca63887adb4a
7
- data.tar.gz: 7f7f9d409053f873d9f7daa9b281b7c926d3b314fe5a2e7bd0814d3a7b5fdf4f8c5f61c6eed9f65a5fd4c3d11665a0efc5464164636e9affd0bac96f95d3798f
6
+ metadata.gz: 99cc273ca6010c9ce2c451e7a7cb3795e4b264b670fb8009436e5b9ddbaacf388e894f0922926bf92113ebf9f211636f4b4fc2a34fc01babcf848327bba798f8
7
+ data.tar.gz: 3686a34890b5438e5d0ca878cbb0bfb89386f2150267c73ef27754d207c6f918aad3355a312045251d3dea15fc2faa6558433f172b907ae4e913c7b60cc204f4
@@ -4,9 +4,13 @@ require 'kameleoon/targeting/models'
4
4
  require 'kameleoon/request'
5
5
  require 'kameleoon/exceptions'
6
6
  require 'kameleoon/cookie'
7
+ require 'kameleoon/data/user_agent'
7
8
  require 'kameleoon/configuration/feature_flag'
8
9
  require 'kameleoon/configuration/variation'
9
10
  require 'kameleoon/configuration/settings'
11
+ require 'kameleoon/network/activity_event'
12
+ require 'kameleoon/network/experiment_event'
13
+ require 'kameleoon/network/url_provider'
10
14
  require 'kameleoon/real_time/real_time_configuration_service'
11
15
  require 'kameleoon/storage/variation_storage'
12
16
  require 'kameleoon/hybrid/manager'
@@ -39,9 +43,8 @@ module Kameleoon
39
43
  @default_timeout = config['default_timeout'] || default_timeout # in ms
40
44
  refresh_interval = config['actions_configuration_refresh_interval']
41
45
  @interval = refresh_interval.nil? ? interval : "#{refresh_interval}m"
42
- @tracking_url = config['tracking_url'] || API_SSX_URL
43
- @api_data_url = 'https://api-data.kameleoon.com'
44
- @events_url = 'https://events.kameleoon.com:8110/'
46
+ data_api_url = config['tracking_url'] || Network::UrlProvider::DEFAULT_DATA_API_URL
47
+ @url_provider = Network::UrlProvider.new(@site_code, data_api_url)
45
48
  @real_time_configuration_service = nil
46
49
  @update_configuration_handler = nil
47
50
  @fetch_configuration_update_job = nil
@@ -129,22 +132,22 @@ module Kameleoon
129
132
  "Experiment #{experiment_id} is not found"
130
133
  end
131
134
  check_site_code_enable(experiment)
132
- if check_targeting(visitor_code, experiment_id, experiment)
135
+ targeted = check_targeting(visitor_code, experiment_id, experiment)
136
+ if targeted
133
137
  # saved_variation = get_valid_saved_variation(visitor_code, experiment)
134
138
  variation_id = calculate_variation_for_experiment(visitor_code, experiment)
135
- if !variation_id.nil?
136
- track_experiment(visitor_code, experiment_id, variation_id)
137
- save_variation(visitor_code, experiment_id, variation_id)
138
- variation_id
139
- else
140
- track_experiment(visitor_code, experiment_id, REFERENCE, true)
141
- raise Exception::NotAllocated.new(visitor_code),
142
- "Experiment #{experiment_id} is not active for visitor #{visitor_code}"
143
- end
144
- else
139
+ save_variation(visitor_code, experiment_id, variation_id)
140
+ end
141
+ _send_tracking_request(visitor_code, experiment_id, variation_id)
142
+ unless targeted
145
143
  raise Exception::NotTargeted.new(visitor_code),
146
144
  "Experiment #{experiment_id} is not targeted for visitor #{visitor_code}"
147
145
  end
146
+ if variation_id.nil?
147
+ raise Exception::NotAllocated.new(visitor_code),
148
+ "Experiment #{experiment_id} is not active for visitor #{visitor_code}"
149
+ end
150
+ variation_id
148
151
  end
149
152
 
150
153
  ##
@@ -208,7 +211,7 @@ module Kameleoon
208
211
  def flush(visitor_code = nil)
209
212
  check_visitor_code(visitor_code) unless visitor_code.nil?
210
213
  if !visitor_code.nil?
211
- track_data(visitor_code)
214
+ _send_tracking_request(visitor_code)
212
215
  else
213
216
  @data.select { |_, values| values.any? { |data| !data.sent } }.each_key { |key| flush(key) }
214
217
  end
@@ -384,7 +387,7 @@ module Kameleoon
384
387
  end
385
388
 
386
389
  ##
387
- # The get_remote_date method allows you to retrieve data (according to a key passed as argument)
390
+ # The get_remote_data method allows you to retrieve data (according to a key passed as argument)
388
391
  # stored on a remote Kameleoon server. Usually data will be stored on our remote
389
392
  # servers via the use of our Data API.
390
393
  # This method, along with the availability of our highly scalable servers for this purpose, provides a convenient
@@ -395,11 +398,11 @@ module Kameleoon
395
398
  # This field is optional.
396
399
  #
397
400
  # @return [Hash] Hash object of the json object.
398
- def get_remote_date(key, timeout = @default_timeout)
401
+ def get_remote_data(key, timeout = @default_timeout)
399
402
  connexion_options = { connect_timeout: (timeout.to_f / 1000.0) }
400
- path = get_api_data_request_url(key)
403
+ url = @url_provider.make_api_data_get_request_url(key)
401
404
  log "Retrieve API Data connexion: #{connexion_options.inspect}"
402
- response = get_sync(@api_data_url + path, connexion_options)
405
+ response = get_sync(url, connexion_options)
403
406
  return nil unless successful_sync?(response)
404
407
 
405
408
  JSON.parse(response.body) unless response.nil?
@@ -409,7 +412,7 @@ module Kameleoon
409
412
  # DEPRECATED. Please use `get_feature_variable` instead.
410
413
  def retrieve_data_from_remote_source(key, timeout = @default_timeout)
411
414
  warn '[DEPRECATION] `retrieve_data_from_remote_source` is deprecated. Please use `get_remote_date` instead.'
412
- get_remote_date(key, timeout)
415
+ get_remote_data(key, timeout)
413
416
  end
414
417
 
415
418
  ##
@@ -490,7 +493,6 @@ module Kameleoon
490
493
 
491
494
  private
492
495
 
493
- API_SSX_URL = 'https://api-ssx.kameleoon.com'
494
496
  REFERENCE = 0
495
497
  DEFAULT_ENVIRONMENT = 'production'
496
498
  CACHE_EXPIRATION_TIMEOUT = 5
@@ -507,7 +509,7 @@ module Kameleoon
507
509
  def fetch_configuration_job(time_stamp = nil)
508
510
  EM.synchrony do
509
511
  begin
510
- ok = obtain_configuration(@site_code, @environment, time_stamp)
512
+ ok = obtain_configuration(@environment, time_stamp)
511
513
  if !ok && @settings.real_time_update
512
514
  @settings.real_time_update = false
513
515
  log('Switching to polling mode due to failed fetch')
@@ -540,10 +542,10 @@ module Kameleoon
540
542
  def start_real_time_configuration_service_if_needed
541
543
  return unless @real_time_configuration_service.nil?
542
544
 
543
- events_url = "#{@events_url}sse?siteCode=#{@site_code}"
545
+ url = @url_provider.make_real_time_url
544
546
  fetch_func = proc { |real_time_event| fetch_configuration_job(real_time_event.time_stamp) }
545
547
  @real_time_configuration_service =
546
- Kameleoon::RealTime::RealTimeConfigurationService.new(events_url, fetch_func, method(:log))
548
+ Kameleoon::RealTime::RealTimeConfigurationService.new(url, fetch_func, method(:log))
547
549
  end
548
550
 
549
551
  def stop_real_time_configuration_service_if_needed
@@ -577,12 +579,10 @@ module Kameleoon
577
579
  # { 'field' => field, 'operator' => operator, 'parameters' => parameters }
578
580
  # end
579
581
 
580
- def obtain_configuration(site_code, environment = @environment, time_stamp = nil)
582
+ def obtain_configuration(environment = @environment, time_stamp = nil)
581
583
  log 'Fetching configuration from Client-Config service'
582
- request_path = "mobile?siteCode=#{site_code}"
583
- request_path += "&environment=#{environment}" unless environment.nil?
584
- request_path += "&ts=#{time_stamp}" unless time_stamp.nil?
585
- request = request_configuration(request_path)
584
+ url = @url_provider.make_configuration_url(environment, time_stamp)
585
+ request = request_configuration(url)
586
586
  return false unless request
587
587
 
588
588
  configuration = JSON.parse(request.response)
@@ -616,8 +616,8 @@ module Kameleoon
616
616
  nil
617
617
  end
618
618
 
619
- def request_configuration(path)
620
- request = EM::Synchrony.sync get({ path: path }, CLIENT_CONFIG_URL)
619
+ def request_configuration(url)
620
+ request = EM::Synchrony.sync get({}, url)
621
621
  unless successful?(request)
622
622
  log "Failed to fetch #{request.inspect}"
623
623
  return false
@@ -625,37 +625,6 @@ module Kameleoon
625
625
  request
626
626
  end
627
627
 
628
- def get_common_ssx_parameters(visitor_code)
629
- {
630
- nonce: Kameleoon::Utils.generate_random_string(16),
631
- siteCode: @site_code,
632
- visitorCode: visitor_code
633
- }
634
- end
635
-
636
- def get_experiment_register_url(visitor_code, experiment_id, variation_id = nil, none_variation = false)
637
- url = "/experimentTracking?#{URI.encode_www_form(get_common_ssx_parameters(visitor_code))}"
638
- url += "&experimentId=#{experiment_id}"
639
- return url if variation_id.nil?
640
-
641
- url += "&variationId=#{variation_id}"
642
- url += '&noneVariation=true' if none_variation
643
-
644
- url
645
- end
646
-
647
- def get_data_register_url(visitor_code)
648
- "/dataTracking?#{URI.encode_www_form(get_common_ssx_parameters(visitor_code))}"
649
- end
650
-
651
- def get_api_data_request_url(key)
652
- mapKey = {
653
- siteCode: site_code,
654
- key: key
655
- }
656
- "/data?#{URI.encode_www_form(mapKey)}"
657
- end
658
-
659
628
  def find_feature_flag(feature_key)
660
629
  if feature_key.is_a?(String)
661
630
  feature_flag = @feature_flags.select { |ff| ff.feature_key == feature_key }.first
@@ -669,67 +638,6 @@ module Kameleoon
669
638
  feature_flag
670
639
  end
671
640
 
672
- def track_experiment(visitor_code, experiment_id, variation_id = nil, none_variation: false)
673
- data_not_sent = data_not_sent(visitor_code)
674
- options = {
675
- path: get_experiment_register_url(visitor_code, experiment_id, variation_id, none_variation),
676
- body: (data_not_sent.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8'),
677
- head: { 'Content-Type': 'text/plain' }
678
- }
679
- set_user_agent_to_headers(visitor_code, options[:head])
680
- trial = 0
681
- success = false
682
- log "Start post tracking experiment: #{data_not_sent.inspect}"
683
- Thread.new do
684
- while trial < 10
685
- log "Send Experiment Tracking #{options.inspect}"
686
- response = post_sync(options, @tracking_url)
687
- log "Response #{response.inspect}"
688
- if successful_sync?(response)
689
- data_not_sent.each { |it| it.sent = true }
690
- success = true
691
- break
692
- end
693
- trial += 1
694
- end
695
- if success
696
- log "Post to experiment tracking is done after #{trial + 1} trials"
697
- else
698
- log "Post to experiment tracking is failed after #{trial} trials"
699
- end
700
- end
701
- end
702
-
703
- def track_data(visitor_code)
704
- Thread.new do
705
- trials = 0
706
- data_not_sent = data_not_sent(visitor_code)
707
- log "Start post tracking data: #{data_not_sent.inspect}"
708
- while trials < 10 && !data_not_sent.empty?
709
- options = {
710
- path: get_data_register_url(visitor_code),
711
- body: (data_not_sent.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8'),
712
- head: { 'Content-Type': 'text/plain' }
713
- }
714
- set_user_agent_to_headers(visitor_code, options[:head])
715
- log "Post tracking data for visitor_code: #{visitor_code} with options: #{options.inspect}"
716
- response = post_sync(options, @tracking_url)
717
- log "Response #{response.inspect}"
718
- if successful_sync?(response)
719
- data_not_sent.each { |it| it.sent = true }
720
- success = true
721
- break
722
- end
723
- trials += 1
724
- end
725
- if success
726
- log "Post to data tracking is done after #{trials + 1} trials"
727
- else
728
- log "Post to data tracking is failed after #{trials} trials"
729
- end
730
- end
731
- end
732
-
733
641
  def check_site_code_enable(campaign)
734
642
  raise Exception::SiteCodeDisabled.new(site_code), site_code unless campaign.site_enabled
735
643
  end
@@ -770,8 +678,17 @@ module Kameleoon
770
678
  def get_condition_data(type, visitor_code, campaign_id)
771
679
  condition_data = nil
772
680
  case type
773
- when Kameleoon::Targeting::ConditionType::CUSTOM_DATUM
681
+ when Kameleoon::Targeting::ConditionType::CUSTOM_DATUM,
682
+ Kameleoon::Targeting::ConditionType::PAGE_TITLE,
683
+ Kameleoon::Targeting::ConditionType::PAGE_URL,
684
+ Kameleoon::Targeting::ConditionType::DEVICE_TYPE,
685
+ Kameleoon::Targeting::ConditionType::BROWSER,
686
+ Kameleoon::Targeting::ConditionType::CONVERSIONS
774
687
  condition_data = (@data[visitor_code] || []).flatten
688
+ when Kameleoon::Targeting::ConditionType::SDK_LANGUAGE
689
+ condition_data = Kameleoon::Targeting::SdkInfo.new(Kameleoon::SDK_NAME, Kameleoon::SDK_VERSION)
690
+ when Kameleoon::Targeting::ConditionType::VISITOR_CODE
691
+ condition_data = visitor_code
775
692
  when Kameleoon::Targeting::ConditionType::TARGET_EXPERIMENT
776
693
  condition_data = @variation_storage.get_hash_saved_variation_id(visitor_code)
777
694
  when Kameleoon::Targeting::ConditionType::EXCLUSIVE_EXPERIMENT
@@ -790,10 +707,11 @@ module Kameleoon
790
707
  variation, rule = _calculate_variation_key_for_feature(visitor_code, feature_flag)
791
708
  variation_key = _get_variation_key(variation, rule, feature_flag)
792
709
  unless rule.nil?
793
- save_variation(visitor_code, rule.experiment_id, variation.variation_id) unless variation.nil?
710
+ experiment_id = rule.experiment_id
794
711
  variation_id = variation.variation_id unless variation.nil?
795
- _send_tracking_request(visitor_code, rule.experiment_id, variation_id)
712
+ save_variation(visitor_code, experiment_id, variation_id)
796
713
  end
714
+ _send_tracking_request(visitor_code, experiment_id, variation_id)
797
715
  [feature_flag, variation_key]
798
716
  end
799
717
 
@@ -809,11 +727,12 @@ module Kameleoon
809
727
  hash_rule = obtain_hash_double_rule(visitor_code, rule.id, rule.respool_time)
810
728
  # check main expostion for rule with hashRule
811
729
  if hash_rule <= rule.exposition
730
+ return [rule.variation_by_exposition[0], rule] if rule.targeted_delivery_type?
731
+
812
732
  # uses for variation's expositions
813
733
  hash_variation = obtain_hash_double_rule(visitor_code, rule.experiment_id, rule.respool_time)
814
734
  # get variation key with new hashVariation
815
735
  variation = rule.get_variation(hash_variation)
816
- # variation_key can be nil for experiment rules only, for targeted rule will be always exist
817
736
  return [variation, rule] unless variation.nil?
818
737
  # if visitor is targeted for targeted rule then break cycle -> return default
819
738
  elsif rule.targeted_delivery_type?
@@ -833,19 +752,46 @@ module Kameleoon
833
752
  def _get_variation_key(var_by_exp, rule, feature_flag)
834
753
  return var_by_exp.variation_key unless var_by_exp.nil?
835
754
 
836
- return Kameleoon::Configuration::VariationType::VARIATION_OFF if !rule.nil? && rule.experiment_type?
755
+ return Kameleoon::Configuration::VariationType::VARIATION_OFF if !rule.nil? && rule.experimentation_type?
837
756
 
838
757
  feature_flag.default_variation_key
839
758
  end
840
759
 
841
760
  ##
842
761
  # helper method for sending tracking requests for new FF
843
- def _send_tracking_request(visitor_code, experiment_id, variation_id)
844
- if !experiment_id.nil?
845
- variation_reference_id = variation_id || 0
846
- track_experiment(visitor_code, experiment_id, variation_reference_id)
762
+ def _send_tracking_request(visitor_code, experiment_id = nil, variation_id = nil)
763
+ data_not_sent = data_not_sent(visitor_code)
764
+ if experiment_id.nil? || variation_id.nil?
765
+ data_not_sent.append(Network::ActivityEvent.new) if data_not_sent.empty?
847
766
  else
848
- log 'An attempt to send a request with null experimentId was blocked'
767
+ data_not_sent.append(Network::ExperimentEvent.new(experiment_id, variation_id))
768
+ end
769
+ options = {
770
+ body: (data_not_sent.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8'),
771
+ head: { 'Content-Type': 'text/plain' }
772
+ }
773
+ set_user_agent_to_headers(visitor_code, options[:head])
774
+ url = @url_provider.make_tracking_url(visitor_code)
775
+ trial = 0
776
+ success = false
777
+ log "Start post tracking: #{data_not_sent.inspect}"
778
+ Thread.new do
779
+ while trial < 10
780
+ log "Send tracking #{options.inspect}"
781
+ response = post_sync(options, url)
782
+ log "Response #{response.inspect}"
783
+ if successful_sync?(response)
784
+ data_not_sent.each { |it| it.sent = true }
785
+ success = true
786
+ break
787
+ end
788
+ trial += 1
789
+ end
790
+ if success
791
+ log "Post to tracking is done after #{trial + 1} trials"
792
+ else
793
+ log "Post to tracking is failed after #{trial} trials"
794
+ end
849
795
  end
850
796
  end
851
797
 
@@ -45,7 +45,7 @@ module Kameleoon
45
45
  variation_by_exposition.select { |v| v.variation_key == key }.first&.variation_id
46
46
  end
47
47
 
48
- def experiment_type?
48
+ def experimentation_type?
49
49
  @type == RuleType::EXPERIMENTATION
50
50
  end
51
51
 
@@ -0,0 +1,33 @@
1
+ require 'json'
2
+ require_relative 'data'
3
+
4
+ module Kameleoon
5
+ module BrowserType
6
+ CHROME = 0
7
+ INTERNET_EXPLORER = 1
8
+ FIREFOX = 2
9
+ SAFARI = 3
10
+ OPERA = 4
11
+ OTHER = 5
12
+ end
13
+
14
+ # Represents browser data for tracking calls
15
+ class Browser < Data
16
+ attr_reader :type, :version
17
+
18
+ # @param [BrowserType] browser_type Browser type, can be: CHROME, INTERNET_EXPLORER, FIREFOX, SAFARI, OPERA, OTHER
19
+ # @param [float] version Version of browser
20
+ def initialize(browser_type, version = Float::NAN)
21
+ super(DataType::BROWSER)
22
+ @type = browser_type
23
+ @version = version
24
+ end
25
+
26
+ def obtain_full_post_text_line
27
+ nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
28
+ url = "eventType=staticData&browserIndex=#{@type}&nonce=#{nonce}"
29
+ url.concat("&browserVersion=#{@version}") if @version.is_a?(Integer) || (@version.is_a?(Float) && !@version.nan?)
30
+ url
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'data'
5
+
6
+ module Kameleoon
7
+ # Conversion class uses for tracking conversion
8
+ class Conversion < Data
9
+ attr_reader :goal_id, :revenue, :negative
10
+
11
+ # @param [Integer] goal_id Id of the goal associated to the conversion
12
+ # @param [Float] revenue Optional field - Revenue associated to the conversion.
13
+ # @param [Boolean] negative Optional field - If the revenue is negative. By default it's positive.
14
+ def initialize(goal_id, revenue = 0.0, negative = false)
15
+ super(DataType::CONVERSION)
16
+ @goal_id = goal_id
17
+ @revenue = revenue || 0.0
18
+ @negative = negative || false
19
+ end
20
+
21
+ def obtain_full_post_text_line
22
+ nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
23
+ "eventType=conversion&goalId=#{@goal_id}&revenue=#{@revenue}&negative=#{@negative}&nonce=#{nonce}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'data'
5
+
6
+ module Kameleoon
7
+ # Represents any custom data for targeting conditions
8
+ class CustomData < Data
9
+ attr_reader :id, :values
10
+
11
+ # @param [Integer] id Id of the custom data
12
+ # @param [String] value Value of the custom data
13
+ # @param [Array] values Array of values of the custom data
14
+ #
15
+ # @overload
16
+ # @param [Hash] hash Json value encoded in a hash.
17
+ # rubocop:disable Metrics/MethodLength
18
+ def initialize(arg0, *args)
19
+ super(DataType::CUSTOM)
20
+ if arg0.is_a?(Hash)
21
+ hash = arg0
22
+ id = hash['id']
23
+ raise Kameleoon::Exception::NotFound.new('id'), '"id" is mandatory' if id.nil?
24
+
25
+ @id = id.to_s
26
+ value = hash['value']
27
+ values = hash['values']
28
+ if values.nil? && value.nil?
29
+ raise Kameleoon::Exception::NotFound.new('value or values'), '"value" or "values" is mandatory'
30
+ end
31
+
32
+ if values.nil?
33
+ @values = [value]
34
+ else
35
+ @values = values.is_a?(Array) ? values.dup : [values]
36
+ @values.append(value) unless value.nil?
37
+ end
38
+ else
39
+ @id = arg0.to_s
40
+ @values = args
41
+ end
42
+ end
43
+ # rubocop:enable Metrics/MethodLength
44
+
45
+ def obtain_full_post_text_line
46
+ return '' if @values.empty?
47
+
48
+ str_values = JSON.generate(Hash[@values.collect { |k| [k, 1] }])
49
+ nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
50
+ "eventType=customData&index=#{@id}&valuesCountMap=#{self.class.encode(str_values)}&overwrite=true&nonce=#{nonce}"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'kameleoon/exceptions'
5
+
6
+ module Kameleoon
7
+ NONCE_LENGTH = 16
8
+
9
+ module DataType
10
+ CUSTOM = 'CUSTOM'
11
+ BROWSER = 'BROWSER'
12
+ CONVERSION = 'CONVERSION'
13
+ DEVICE = 'DEVICE'
14
+ PAGE_VIEW = 'PAGE_VIEW'
15
+ end
16
+
17
+ # Represents base class for any Kameleoon data
18
+ class Data
19
+ attr_reader :instance
20
+ attr_accessor :sent
21
+
22
+ def initialize(data_type)
23
+ @instance = data_type
24
+ @sent = false
25
+ end
26
+
27
+ def obtain_full_post_text_line
28
+ raise KameleoonError.new('ToDo: implement this method.'), 'ToDo: implement this method.'
29
+ end
30
+
31
+ def self.encode(url)
32
+ Network::UriHelper.encode_uri(url)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'data'
5
+
6
+ module Kameleoon
7
+ module DeviceType
8
+ PHONE = 'PHONE'
9
+ TABLET = 'TABLET'
10
+ DESKTOP = 'DESKTOP'
11
+ end
12
+
13
+ # Device uses for sending deviceType parameter for tracking calls
14
+ class Device < Data
15
+ attr_reader :device_type
16
+ def initialize(device_type)
17
+ super(DataType::DEVICE)
18
+ @device_type = device_type
19
+ end
20
+
21
+ def obtain_full_post_text_line
22
+ nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
23
+ "eventType=staticData&deviceType=#{@device_type}&nonce=#{nonce}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'data'
5
+
6
+ module Kameleoon
7
+ # Represents page view data for tracking calls
8
+ class PageView < Data
9
+ attr_reader :url, :title, :referrer
10
+
11
+ # @param [String] url Url of the page
12
+ # @param [String] title Title of the page
13
+ # @param [Array] referrers Optional field - Referrer ids
14
+ def initialize(url, title, referrers = nil)
15
+ super(DataType::PAGE_VIEW)
16
+ @url = url || ''
17
+ @title = title || ''
18
+ @referrers = referrers.instance_of?(Integer) ? [referrers] : referrers
19
+ end
20
+
21
+ def obtain_full_post_text_line
22
+ nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
23
+ referrer_text = if !@referrers.nil? && !@referrers.empty?
24
+ "&referrersIndices=%5B#{@referrers.each(&:to_s).join('%2C')}%5D"
25
+ else
26
+ ''
27
+ end
28
+ "eventType=page&href=#{self.class.encode(@url)}&title=#{self.class.encode(@title)}#{referrer_text}&nonce=#{nonce}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Kameleoon
6
+ # UserAgent uses for changing User-Agent header for tracking calls
7
+ class UserAgent
8
+ attr_reader :value
9
+
10
+ def initialize(value)
11
+ @value = value
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'kameleoon/data/data'
5
+ require 'kameleoon/utils'
6
+ require 'kameleoon/network/uri_helper'
7
+
8
+ module Kameleoon
9
+ module Network
10
+ ##
11
+ # ActivityEvent represents an activity tracking event.
12
+ class ActivityEvent
13
+ EVENT_TYPE = 'activity'
14
+
15
+ attr_accessor :sent
16
+
17
+ def initialize
18
+ @sent = false
19
+ @nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
20
+ end
21
+
22
+ def obtain_full_post_text_line
23
+ params = {
24
+ eventType: EVENT_TYPE,
25
+ nonce: @nonce
26
+ }
27
+ UriHelper.encode_query(params)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'kameleoon/data/data'
5
+ require 'kameleoon/utils'
6
+ require 'kameleoon/network/uri_helper'
7
+
8
+ module Kameleoon
9
+ module Network
10
+ ##
11
+ # ExperimentEvent represents an experiment tracking event.
12
+ class ExperimentEvent
13
+ EVENT_TYPE = 'experiment'
14
+
15
+ attr_accessor :sent
16
+
17
+ def initialize(experiment_id, variation_id)
18
+ @sent = false
19
+ @experiment_id = experiment_id
20
+ @variation_id = variation_id
21
+ @nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
22
+ end
23
+
24
+ def obtain_full_post_text_line
25
+ params = {
26
+ eventType: EVENT_TYPE,
27
+ id: @experiment_id,
28
+ variationId: @variation_id,
29
+ nonce: @nonce
30
+ }
31
+ UriHelper.encode_query(params)
32
+ end
33
+ end
34
+ end
35
+ end