kameleoon-client-ruby 3.1.1 → 3.2.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/kameleoon/configuration/custom_data_info.rb +43 -0
- data/lib/kameleoon/configuration/data_file.rb +30 -2
- data/lib/kameleoon/configuration/rule.rb +4 -1
- data/lib/kameleoon/configuration/variation_exposition.rb +1 -1
- data/lib/kameleoon/data/browser.rb +19 -0
- data/lib/kameleoon/data/cookie.rb +14 -0
- data/lib/kameleoon/data/custom_data.rb +2 -0
- data/lib/kameleoon/data/data.rb +2 -0
- data/lib/kameleoon/data/geolocation.rb +45 -0
- data/lib/kameleoon/data/manager/assigned_variation.rb +2 -1
- data/lib/kameleoon/data/manager/page_view_visit.rb +16 -2
- data/lib/kameleoon/data/manager/visitor.rb +64 -14
- data/lib/kameleoon/data/manager/visitor_manager.rb +23 -1
- data/lib/kameleoon/data/operating_system.rb +72 -0
- data/lib/kameleoon/data/page_view.rb +2 -2
- data/lib/kameleoon/data/visitor_visits.rb +13 -0
- data/lib/kameleoon/kameleoon_client.rb +75 -94
- data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +57 -0
- data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +162 -0
- data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +3 -1
- data/lib/kameleoon/network/access_token_source.rb +22 -5
- data/lib/kameleoon/network/network_manager.rb +10 -10
- data/lib/kameleoon/network/response.rb +1 -1
- data/lib/kameleoon/network/url_provider.rb +15 -12
- data/lib/kameleoon/targeting/condition.rb +22 -2
- data/lib/kameleoon/targeting/condition_factory.rb +36 -6
- data/lib/kameleoon/targeting/conditions/cookie_condition.rb +55 -0
- data/lib/kameleoon/targeting/conditions/exclusive_feature_flag_condition.rb +27 -0
- data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +33 -0
- data/lib/kameleoon/targeting/conditions/number_condition.rb +38 -0
- data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +27 -0
- data/lib/kameleoon/targeting/conditions/page_view_number_condition.rb +28 -0
- data/lib/kameleoon/targeting/conditions/previous_page_condition.rb +35 -0
- data/lib/kameleoon/targeting/conditions/segment_condition.rb +42 -0
- data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +63 -0
- data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +30 -0
- data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +28 -0
- data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +33 -0
- data/lib/kameleoon/targeting/targeting_manager.rb +66 -0
- data/lib/kameleoon/types/remote_visitor_data_filter.rb +24 -0
- data/lib/kameleoon/utils.rb +1 -0
- data/lib/kameleoon/version.rb +1 -1
- metadata +24 -4
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -18
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +0 -45
@@ -45,17 +45,17 @@ module Kameleoon
|
|
45
45
|
make_call(request, true)
|
46
46
|
end
|
47
47
|
|
48
|
-
def get_remote_visitor_data(visitor_code, timeout = nil)
|
49
|
-
url = @url_provider.make_visitor_data_get_url(visitor_code)
|
48
|
+
def get_remote_visitor_data(visitor_code, filter, is_unique_identifier, timeout = nil)
|
49
|
+
url = @url_provider.make_visitor_data_get_url(visitor_code, filter, is_unique_identifier)
|
50
50
|
timeout = ensure_timeout(timeout)
|
51
51
|
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
52
52
|
make_call(request, true)
|
53
53
|
end
|
54
54
|
|
55
|
-
def send_tracking_data(visitor_code, lines, user_agent, timeout = nil)
|
55
|
+
def send_tracking_data(visitor_code, lines, user_agent, is_unique_identifier, timeout = nil)
|
56
56
|
return if lines.nil? || lines.empty?
|
57
57
|
|
58
|
-
url = @url_provider.make_tracking_url(visitor_code)
|
58
|
+
url = @url_provider.make_tracking_url(visitor_code, is_unique_identifier)
|
59
59
|
timeout = ensure_timeout(timeout)
|
60
60
|
data = (lines.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8')
|
61
61
|
request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent: user_agent, data: data)
|
@@ -87,11 +87,13 @@ module Kameleoon
|
|
87
87
|
delay(retry_delay) if attempt.positive? && retry_delay.positive?
|
88
88
|
try_authorize(request) if try_access_token_auth
|
89
89
|
response = @sync_net_provider.make_request(request)
|
90
|
-
if
|
90
|
+
if response.success?
|
91
|
+
success = true
|
92
|
+
elsif !response.error.nil?
|
91
93
|
log_failure(request, "Error occurred during request: #{response.error}")
|
92
|
-
|
94
|
+
else
|
93
95
|
log_failure(request, "Received unexpected status code '#{response.code}'")
|
94
|
-
if
|
96
|
+
if response.code == 401 && request.access_token
|
95
97
|
@log_func&.call("Unexpected rejection of access token '#{request.access_token}'")
|
96
98
|
@access_token_source.discard_token(request.access_token)
|
97
99
|
if attempt == retry_limit
|
@@ -101,8 +103,6 @@ module Kameleoon
|
|
101
103
|
attempt -= 1
|
102
104
|
end
|
103
105
|
end
|
104
|
-
else
|
105
|
-
success = true
|
106
106
|
end
|
107
107
|
attempt += 1
|
108
108
|
end
|
@@ -126,7 +126,7 @@ module Kameleoon
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def try_authorize(request)
|
129
|
-
token = @access_token_source.get_token
|
129
|
+
token = @access_token_source.get_token(request.timeout)
|
130
130
|
request.authorize(token)
|
131
131
|
end
|
132
132
|
end
|
@@ -37,25 +37,28 @@ module Kameleoon
|
|
37
37
|
@data_api_domain = domain if domain.is_a?(String)
|
38
38
|
end
|
39
39
|
|
40
|
-
def make_tracking_url(visitor_code)
|
40
|
+
def make_tracking_url(visitor_code, is_unique_identifier = false)
|
41
41
|
params = {
|
42
42
|
sdkName: SDK_NAME,
|
43
43
|
sdkVersion: SDK_VERSION,
|
44
|
-
siteCode: @site_code
|
45
|
-
visitorCode: visitor_code
|
44
|
+
siteCode: @site_code
|
46
45
|
}
|
46
|
+
params[is_unique_identifier ? :mappingValue : :visitorCode] = visitor_code
|
47
47
|
"https://#{@data_api_domain}#{TRACKING_PATH}?#{UriHelper.encode_query(params)}"
|
48
48
|
end
|
49
49
|
|
50
|
-
def make_visitor_data_get_url(visitor_code)
|
51
|
-
params = {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
50
|
+
def make_visitor_data_get_url(visitor_code, filter, is_unique_identifier = false)
|
51
|
+
params = { siteCode: @site_code }
|
52
|
+
params[is_unique_identifier ? :mappingValue : :visitorCode] = visitor_code
|
53
|
+
params[:maxNumberPreviousVisits] = filter.previous_visit_amount
|
54
|
+
params[:version] = 0
|
55
|
+
params[:currentVisit] = filter.current_visit if filter.current_visit
|
56
|
+
params[:customData] = filter.custom_data if filter.custom_data
|
57
|
+
params[:conversion] = filter.conversions if filter.conversions
|
58
|
+
params[:geolocation] = filter.geolocation if filter.geolocation
|
59
|
+
params[:experiment] = filter.experiments if filter.experiments
|
60
|
+
params[:page] = filter.page_views if filter.page_views
|
61
|
+
params[:staticData] = true if filter.device || filter.browser || filter.operating_system
|
59
62
|
"https://#{@data_api_domain}#{VISITOR_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
60
63
|
end
|
61
64
|
|
@@ -6,15 +6,26 @@ module Kameleoon
|
|
6
6
|
module Targeting
|
7
7
|
module ConditionType
|
8
8
|
CUSTOM_DATUM = 'CUSTOM_DATUM'
|
9
|
-
|
10
|
-
|
9
|
+
TARGET_FEATURE_FLAG = 'TARGET_FEATURE_FLAG'
|
10
|
+
EXCLUSIVE_FEATURE_FLAG = 'EXCLUSIVE_FEATURE_FLAG'
|
11
11
|
PAGE_URL = 'PAGE_URL'
|
12
|
+
PAGE_VIEWS = 'PAGE_VIEWS'
|
13
|
+
PREVIOUS_PAGE = 'PREVIOUS_PAGE'
|
12
14
|
PAGE_TITLE = 'PAGE_TITLE'
|
13
15
|
VISITOR_CODE = 'VISITOR_CODE'
|
14
16
|
DEVICE_TYPE = 'DEVICE_TYPE'
|
15
17
|
BROWSER = 'BROWSER'
|
16
18
|
SDK_LANGUAGE = 'SDK_LANGUAGE'
|
17
19
|
CONVERSIONS = 'CONVERSIONS'
|
20
|
+
COOKIE = 'COOKIE'
|
21
|
+
OPERATING_SYSTEM = 'OPERATING_SYSTEM'
|
22
|
+
GEOLOCATION = 'GEOLOCATION'
|
23
|
+
SEGMENT = 'SEGMENT'
|
24
|
+
FIRST_VISIT = 'FIRST_VISIT'
|
25
|
+
LAST_VISIT = 'LAST_VISIT'
|
26
|
+
VISITS = 'VISITS'
|
27
|
+
SAME_DAY_VISITS = 'SAME_DAY_VISITS'
|
28
|
+
NEW_VISITORS = 'NEW_VISITORS'
|
18
29
|
end
|
19
30
|
|
20
31
|
module Operator
|
@@ -52,6 +63,15 @@ module Kameleoon
|
|
52
63
|
def get_last_targeting_data(list_data, data_type)
|
53
64
|
list_data.select { |data| data.instance == data_type }.last
|
54
65
|
end
|
66
|
+
|
67
|
+
def is_regex_match(value, pattern)
|
68
|
+
begin
|
69
|
+
return pattern.match? value
|
70
|
+
rescue StandardError => e
|
71
|
+
log "Failed to match with regex (targeting): #{e}"
|
72
|
+
end
|
73
|
+
false
|
74
|
+
end
|
55
75
|
end
|
56
76
|
end
|
57
77
|
end
|
@@ -1,13 +1,23 @@
|
|
1
1
|
require_relative 'conditions/custom_datum'
|
2
|
-
require_relative 'conditions/
|
3
|
-
require_relative 'conditions/
|
2
|
+
require_relative 'conditions/target_feature_flag_condition'
|
3
|
+
require_relative 'conditions/exclusive_feature_flag_condition'
|
4
4
|
require_relative 'conditions/page_title_condition'
|
5
5
|
require_relative 'conditions/page_url_condition'
|
6
|
+
require_relative 'conditions/page_view_number_condition'
|
7
|
+
require_relative 'conditions/previous_page_condition'
|
6
8
|
require_relative 'conditions/visitor_code_condition'
|
7
9
|
require_relative 'conditions/device_condition'
|
8
10
|
require_relative 'conditions/conversion_condition'
|
9
11
|
require_relative 'conditions/browser_condition'
|
10
12
|
require_relative 'conditions/sdk_language_condition'
|
13
|
+
require_relative 'conditions/geolocation_condition'
|
14
|
+
require_relative 'conditions/operating_system_condition'
|
15
|
+
require_relative 'conditions/cookie_condition'
|
16
|
+
require_relative 'conditions/segment_condition'
|
17
|
+
require_relative 'conditions/visit_number_total_condition'
|
18
|
+
require_relative 'conditions/visit_number_today_condition'
|
19
|
+
require_relative 'conditions/visitor_new_return_condition'
|
20
|
+
require_relative 'conditions/time_elapsed_since_visit_condition'
|
11
21
|
require_relative 'conditions/unknown_condition'
|
12
22
|
|
13
23
|
module Kameleoon
|
@@ -19,12 +29,16 @@ module Kameleoon
|
|
19
29
|
case condition_json['targetingType']
|
20
30
|
when ConditionType::CUSTOM_DATUM
|
21
31
|
CustomDatum.new(condition_json)
|
22
|
-
when ConditionType::
|
23
|
-
|
24
|
-
when ConditionType::
|
25
|
-
|
32
|
+
when ConditionType::TARGET_FEATURE_FLAG
|
33
|
+
TargetFeatureFlagCondition.new(condition_json)
|
34
|
+
when ConditionType::EXCLUSIVE_FEATURE_FLAG
|
35
|
+
ExclusiveFeatureFlagCondition.new(condition_json)
|
26
36
|
when ConditionType::PAGE_URL
|
27
37
|
PageUrlCondition.new(condition_json)
|
38
|
+
when ConditionType::PAGE_VIEWS
|
39
|
+
PageViewNumberCondition.new(condition_json)
|
40
|
+
when ConditionType::PREVIOUS_PAGE
|
41
|
+
PreviousPageCondition.new(condition_json)
|
28
42
|
when ConditionType::PAGE_TITLE
|
29
43
|
PageTitleCondition.new(condition_json)
|
30
44
|
when ConditionType::VISITOR_CODE
|
@@ -37,6 +51,22 @@ module Kameleoon
|
|
37
51
|
BrowserCondition.new(condition_json)
|
38
52
|
when ConditionType::SDK_LANGUAGE
|
39
53
|
SdkLanguageCondition.new(condition_json)
|
54
|
+
when ConditionType::GEOLOCATION
|
55
|
+
GeolocationCondition.new(condition_json)
|
56
|
+
when ConditionType::OPERATING_SYSTEM
|
57
|
+
OperatingSystemCondition.new(condition_json)
|
58
|
+
when ConditionType::COOKIE
|
59
|
+
CookieCondition.new(condition_json)
|
60
|
+
when ConditionType::SEGMENT
|
61
|
+
SegmentCondition.new(condition_json)
|
62
|
+
when ConditionType::VISITS
|
63
|
+
VisitNumberTotalCondition.new(condition_json)
|
64
|
+
when ConditionType::SAME_DAY_VISITS
|
65
|
+
VisitNumberTodayCondition.new(condition_json)
|
66
|
+
when ConditionType::NEW_VISITORS
|
67
|
+
VisitorNewReturnCondition.new(condition_json)
|
68
|
+
when ConditionType::FIRST_VISIT, ConditionType::LAST_VISIT
|
69
|
+
TimeElapsedSinceVisitCondition.new(condition_json)
|
40
70
|
else
|
41
71
|
UnknownCondition.new(condition_json)
|
42
72
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/cookie'
|
4
|
+
require 'kameleoon/version'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class CookieCondition < Condition
|
11
|
+
def initialize(json_condition)
|
12
|
+
super(json_condition)
|
13
|
+
@condition_name = json_condition['name']
|
14
|
+
@name_match_type = json_condition['nameMatchType']
|
15
|
+
@condition_value = json_condition['value']
|
16
|
+
@value_match_type = json_condition['valueMatchType']
|
17
|
+
end
|
18
|
+
|
19
|
+
def check(cookie)
|
20
|
+
cookie.is_a?(Kameleoon::Cookie) && check_values(select_values(cookie))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def select_values(cookie)
|
26
|
+
case @name_match_type
|
27
|
+
when Kameleoon::Targeting::Operator::EXACT
|
28
|
+
value = cookie.cookies[@condition_name]
|
29
|
+
return value != nil ? [value] : []
|
30
|
+
when Kameleoon::Targeting::Operator::CONTAINS
|
31
|
+
return cookie.cookies.select{|key| key.include? @condition_name}.values()
|
32
|
+
when Kameleoon::Targeting::Operator::REGULAR_EXPRESSION
|
33
|
+
return cookie.cookies.select{|key| is_regex_match(@condition_name, key)}.values()
|
34
|
+
else
|
35
|
+
log "Unexpected comparing operation for Cookie condition (name): #{@name_match_type}"
|
36
|
+
end
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_values(values)
|
41
|
+
case @value_match_type
|
42
|
+
when Kameleoon::Targeting::Operator::EXACT
|
43
|
+
return values.any? {|value| value == @condition_value}
|
44
|
+
when Kameleoon::Targeting::Operator::CONTAINS
|
45
|
+
return values.any? {|value| value.include? @condition_value}
|
46
|
+
when Kameleoon::Targeting::Operator::REGULAR_EXPRESSION
|
47
|
+
return values.any? {|value| is_regex_match(@condition_value, value)}
|
48
|
+
else
|
49
|
+
log "Unexpected comparing operation for Cookie condition (name): #{@name_match_type}"
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/condition'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# @api private
|
7
|
+
module Targeting
|
8
|
+
# ExclusiveExperiment represents an instance of Exclusive Experiment condition in user account
|
9
|
+
class ExclusiveFeatureFlagCondition < Condition
|
10
|
+
def check(data)
|
11
|
+
return false unless data.is_a?(ExclusiveFeatureFlagInfo)
|
12
|
+
|
13
|
+
size = data.variations_storage&.size || 0
|
14
|
+
size.zero? || (size == 1 && !data.variations_storage.get(data.current_experiment_id).nil?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ExclusiveFeatureFlagInfo
|
19
|
+
attr_reader :current_experiment_id, :variations_storage
|
20
|
+
|
21
|
+
def initialize(current_experiment_id, variations_storage)
|
22
|
+
@current_experiment_id = current_experiment_id
|
23
|
+
@variations_storage = variations_storage
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/geolocation'
|
4
|
+
require 'kameleoon/version'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class GeolocationCondition < Condition
|
11
|
+
def initialize(json_condition)
|
12
|
+
super(json_condition)
|
13
|
+
@country = json_condition['country']
|
14
|
+
@region = json_condition['region']
|
15
|
+
@city = json_condition['city']
|
16
|
+
end
|
17
|
+
|
18
|
+
def check(geolocation)
|
19
|
+
geolocation.is_a?(Kameleoon::Geolocation) && check_targeting(geolocation)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def check_targeting(geolocation)
|
25
|
+
return false if !@country.is_a?(String) || !@country.casecmp?(geolocation.country)
|
26
|
+
return false if @region.is_a?(String) && !@region.casecmp?(geolocation.region)
|
27
|
+
return false if @city.is_a?(String) && !@city.casecmp?(geolocation.city)
|
28
|
+
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/cookie'
|
4
|
+
require 'kameleoon/version'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class NumberCondition < Condition
|
11
|
+
def initialize(json_condition, value)
|
12
|
+
super(json_condition)
|
13
|
+
@match_type = json_condition['matchType']
|
14
|
+
@condition_value = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def check(value)
|
18
|
+
check_targeting(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def check_targeting(value)
|
24
|
+
case @match_type
|
25
|
+
when Kameleoon::Targeting::Operator::EQUAL
|
26
|
+
return value == @condition_value
|
27
|
+
when Kameleoon::Targeting::Operator::GREATER
|
28
|
+
return @condition_value != nil && value > @condition_value
|
29
|
+
when Kameleoon::Targeting::Operator::LOWER
|
30
|
+
return @condition_value != nil && value < @condition_value
|
31
|
+
else
|
32
|
+
log "Unexpected comparing operation for #{type} condition: #{@match_type}"
|
33
|
+
end
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/operating_system'
|
4
|
+
require 'kameleoon/version'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class OperatingSystemCondition < Condition
|
11
|
+
def initialize(json_condition)
|
12
|
+
super(json_condition)
|
13
|
+
@os_type = Kameleoon::OperatingSystemType.from_name(json_condition['os'])
|
14
|
+
end
|
15
|
+
|
16
|
+
def check(operating_system)
|
17
|
+
operating_system.is_a?(Kameleoon::OperatingSystem) && check_targeting(operating_system)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def check_targeting(operating_system)
|
23
|
+
@os_type != nil && operating_system.os_type == @os_type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/conditions/number_condition'
|
4
|
+
require 'kameleoon/data/manager/page_view_visit'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class PageViewNumberCondition < NumberCondition
|
11
|
+
def initialize(json_condition)
|
12
|
+
page_count = json_condition['pageCount']
|
13
|
+
super(json_condition, page_count)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check(page_view_visit_storage)
|
17
|
+
return false unless page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
|
18
|
+
|
19
|
+
count = 0
|
20
|
+
page_view_visit_storage.enumerate do |visit|
|
21
|
+
return false unless visit.is_a?(Kameleoon::DataManager::PageViewVisit)
|
22
|
+
count += visit.count
|
23
|
+
end
|
24
|
+
check_targeting(count)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/conditions/string_value_condition'
|
4
|
+
require 'kameleoon/data/manager/page_view_visit'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class PreviousPageCondition < StringValueCondition
|
11
|
+
def initialize(json_condition)
|
12
|
+
super(json_condition, json_condition['url'])
|
13
|
+
end
|
14
|
+
|
15
|
+
def check(page_view_visit_storage)
|
16
|
+
is_targeted = false
|
17
|
+
if page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
|
18
|
+
most_recent_visit = nil
|
19
|
+
second_most_recent_visit = nil
|
20
|
+
page_view_visit_storage.enumerate do |visit|
|
21
|
+
return false unless visit.is_a?(Kameleoon::DataManager::PageViewVisit)
|
22
|
+
if most_recent_visit == nil || visit.last_timestamp > most_recent_visit.last_timestamp
|
23
|
+
second_most_recent_visit = most_recent_visit
|
24
|
+
most_recent_visit = visit
|
25
|
+
elsif second_most_recent_visit == nil || visit.last_timestamp > second_most_recent_visit.last_timestamp
|
26
|
+
second_most_recent_visit = visit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
is_targeted = second_most_recent_visit != nil && check_targeting(second_most_recent_visit.page_view.url)
|
30
|
+
end
|
31
|
+
is_targeted
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/geolocation'
|
4
|
+
require 'kameleoon/version'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class SegmentCondition < Condition
|
11
|
+
def initialize(json_condition)
|
12
|
+
super(json_condition)
|
13
|
+
@segment_id = json_condition["segmentId"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def check(data)
|
17
|
+
data.is_a?(SegmentInfo) && check_targeting(data)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def check_targeting(segment_info)
|
23
|
+
rule = segment_info.data_file.rule_by_segment_id[@segment_id]
|
24
|
+
return false unless rule.is_a?(Kameleoon::Configuration::Rule)
|
25
|
+
rule.targeting_segment.check_tree(->(type) {segment_info.condition_data(type)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class SegmentInfo
|
30
|
+
attr_reader :data_file
|
31
|
+
|
32
|
+
def initialize(data_file, condition_data)
|
33
|
+
@data_file = data_file
|
34
|
+
@condition_data = condition_data
|
35
|
+
end
|
36
|
+
|
37
|
+
def condition_data(type)
|
38
|
+
@condition_data.call(type)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/condition'
|
4
|
+
require 'kameleoon/exceptions'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
# TargetExperiment represents an instance of Experiment condition in user account
|
10
|
+
class TargetFeatureFlagCondition < Condition
|
11
|
+
include Kameleoon::Exception
|
12
|
+
|
13
|
+
def initialize(json_condition)
|
14
|
+
super(json_condition)
|
15
|
+
|
16
|
+
@feature_flag_id = json_condition['featureFlagId']
|
17
|
+
@condition_variation_key = json_condition['variationKey']
|
18
|
+
@condition_rule_id = json_condition['ruleId']
|
19
|
+
end
|
20
|
+
|
21
|
+
def check(data)
|
22
|
+
return false unless data.is_a?(Kameleoon::Targeting::TargetFeatureFlagInfo) && data.variations_storage.size != 0
|
23
|
+
get_rules(data).any? {|rule| check_rule(data, rule)}
|
24
|
+
end
|
25
|
+
|
26
|
+
private def check_rule(data, rule)
|
27
|
+
return false if !rule.is_a?(Kameleoon::Configuration::Rule) || rule.experiment_id == nil
|
28
|
+
|
29
|
+
if @condition_rule_id != nil
|
30
|
+
return false if @condition_rule_id != rule.id
|
31
|
+
end
|
32
|
+
|
33
|
+
variation = data.variations_storage.get(rule.experiment_id)
|
34
|
+
return false if variation == nil
|
35
|
+
|
36
|
+
return true if @condition_variation_key == nil
|
37
|
+
|
38
|
+
variation = data.data_file.variation_by_id[variation.variation_id]
|
39
|
+
|
40
|
+
return false unless variation.is_a?(Kameleoon::Configuration::VariationByExposition)
|
41
|
+
|
42
|
+
variation.variation_key == @condition_variation_key
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_rules(data)
|
46
|
+
feature_flag = data.data_file.feature_flag_by_id[@feature_flag_id]
|
47
|
+
if feature_flag != nil
|
48
|
+
return feature_flag.rules
|
49
|
+
end
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class TargetFeatureFlagInfo
|
55
|
+
attr_reader :data_file, :variations_storage
|
56
|
+
|
57
|
+
def initialize(data_file, variations_storage)
|
58
|
+
@data_file = data_file
|
59
|
+
@variations_storage = variations_storage
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/conditions/number_condition'
|
4
|
+
require 'kameleoon/data/visitor_visits'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class TimeElapsedSinceVisitCondition < NumberCondition
|
11
|
+
def initialize(json_condition)
|
12
|
+
count_in_millis = json_condition['countInMillis']
|
13
|
+
super(json_condition, count_in_millis)
|
14
|
+
@is_first_visit = @type == Kameleoon::Targeting::ConditionType::FIRST_VISIT
|
15
|
+
end
|
16
|
+
|
17
|
+
def check(data)
|
18
|
+
return false unless data.is_a?(Kameleoon::VisitorVisits) && @condition_value != nil
|
19
|
+
|
20
|
+
previous_visits_count = data.previous_visit_timestamps.count
|
21
|
+
if previous_visits_count >= 1
|
22
|
+
now = (Time.now.to_f * 1000).to_i # ... * 1000 for convert seconds to milliseconds
|
23
|
+
visit_time = data.previous_visit_timestamps[@is_first_visit ? previous_visits_count - 1 : 0]
|
24
|
+
return check_targeting(now - visit_time)
|
25
|
+
end
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/visitor_visits'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# @api private
|
8
|
+
module Targeting
|
9
|
+
|
10
|
+
class VisitNumberTodayCondition < NumberCondition
|
11
|
+
def initialize(json_condition)
|
12
|
+
visit_count = json_condition['visitCount']
|
13
|
+
super(json_condition, visit_count)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check(data)
|
17
|
+
return false unless data.is_a?(Kameleoon::VisitorVisits) && @condition_value != nil
|
18
|
+
number_of_visits_today = 0
|
19
|
+
start_of_day = (Time.new.to_date.to_time.to_f * 1000).to_i # ... * 1000 for convert seconds to milliseconds
|
20
|
+
for timestamp in data.previous_visit_timestamps
|
21
|
+
break if timestamp < start_of_day
|
22
|
+
number_of_visits_today += 1
|
23
|
+
end
|
24
|
+
check_targeting(number_of_visits_today + 1) # +1 for current visit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/conditions/number_condition'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# @api private
|
7
|
+
module Targeting
|
8
|
+
|
9
|
+
class VisitNumberTotalCondition < NumberCondition
|
10
|
+
def initialize(json_condition)
|
11
|
+
visit_count = json_condition['visitCount']
|
12
|
+
super(json_condition, visit_count)
|
13
|
+
end
|
14
|
+
|
15
|
+
def check(data)
|
16
|
+
return false unless data.is_a?(Kameleoon::VisitorVisits) && @condition_value != nil
|
17
|
+
check_targeting(data.previous_visit_timestamps.size + 1) # +1 for current visit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|