kameleoon-client-ruby 1.0.9 → 1.0.10
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b70d1fc8cd47248dd68ba217e9a860577008e008cac7e6f562ab1856b3dc24c3
|
|
4
|
+
data.tar.gz: 03ddd4ce4f1ea480bc5adfc347c9f2168af952cc9036ce5cff494af9699a4dfe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d3d39ad2e27a0312ff090f58a93cba6aa69450fd7763fbdc1375bd146bf1af909dde84815073fc7cf7d60b8aa123cb4cc139e8dee19c30aba3a88ae021475633
|
|
7
|
+
data.tar.gz: bfb92b7c42f02fde8d90484efef51abe294eaece630e97e7d0168e7974dd89d06b9069e9226c23bc2cf25755a2c1d4e41c87d114a1093b6e391a04d440f60de7
|
data/lib/kameleoon/client.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'kameleoon/targeting/models'
|
|
2
4
|
require 'kameleoon/request'
|
|
3
5
|
require 'kameleoon/exceptions'
|
|
@@ -32,6 +34,7 @@ module Kameleoon
|
|
|
32
34
|
@client_id = client_id || config['client_id']
|
|
33
35
|
@client_secret = client_secret || config['client_secret']
|
|
34
36
|
@data_maximum_size = config['visitor_data_maximum_size'] || 500 # mb
|
|
37
|
+
@environment = config['environment'] || DEFAULT_ENVIRONMENT
|
|
35
38
|
@verbose_mode = config['verbose_mode'] || false
|
|
36
39
|
@experiments = []
|
|
37
40
|
@feature_flags = []
|
|
@@ -119,6 +122,7 @@ module Kameleoon
|
|
|
119
122
|
end
|
|
120
123
|
variation_id.to_i
|
|
121
124
|
else
|
|
125
|
+
check_site_code_enable(experiment)
|
|
122
126
|
visitor_data = @data.select { |key, value| key.to_s == visitor_code }.values.flatten! || []
|
|
123
127
|
if experiment['targetingSegment'].nil? || experiment['targetingSegment'].check_tree(visitor_data)
|
|
124
128
|
threshold = obtain_hash_double(visitor_code, experiment['respoolTime'], experiment['id'])
|
|
@@ -262,6 +266,7 @@ module Kameleoon
|
|
|
262
266
|
result.to_s != "null"
|
|
263
267
|
|
|
264
268
|
else
|
|
269
|
+
check_site_code_enable(feature_flag)
|
|
265
270
|
visitor_data = @data.select { |key, value| key.to_s == visitor_code }.values.flatten! || []
|
|
266
271
|
unless feature_flag['targetingSegment'].nil? || feature_flag['targetingSegment'].check_tree(visitor_data)
|
|
267
272
|
raise Exception::NotTargeted.new(visitor_code)
|
|
@@ -269,7 +274,7 @@ module Kameleoon
|
|
|
269
274
|
|
|
270
275
|
if is_feature_flag_scheduled(feature_flag, Time.now.to_i)
|
|
271
276
|
threshold = obtain_hash_double(visitor_code, {}, id)
|
|
272
|
-
if threshold
|
|
277
|
+
if threshold >= 1 - feature_flag['expositionRate']
|
|
273
278
|
track_experiment(visitor_code, id, feature_flag["variations"].first['id'])
|
|
274
279
|
true
|
|
275
280
|
else
|
|
@@ -314,21 +319,23 @@ module Kameleoon
|
|
|
314
319
|
end
|
|
315
320
|
|
|
316
321
|
private
|
|
317
|
-
|
|
322
|
+
|
|
323
|
+
API_SSX_URL = 'https://api-ssx.kameleoon.com'
|
|
318
324
|
REFERENCE = 0
|
|
319
|
-
STATUS_ACTIVE =
|
|
320
|
-
FEATURE_STATUS_DEACTIVATED =
|
|
325
|
+
STATUS_ACTIVE = 'ACTIVE'
|
|
326
|
+
FEATURE_STATUS_DEACTIVATED = 'DEACTIVATED'
|
|
327
|
+
DEFAULT_ENVIRONMENT = 'production'
|
|
321
328
|
attr :site_code, :client_id, :client_secret, :access_token, :experiments, :feature_flags, :scheduler, :data,
|
|
322
329
|
:blocking, :tracking_url, :default_timeout, :interval, :memory_limit, :verbose_mode
|
|
323
330
|
|
|
324
331
|
def fetch_configuration
|
|
325
332
|
@scheduler = Rufus::Scheduler.singleton
|
|
326
333
|
@scheduler.every @interval do
|
|
327
|
-
log(
|
|
334
|
+
log('Scheduled job to fetch configuration is starting.')
|
|
328
335
|
fetch_configuration_job_graphql
|
|
329
336
|
end
|
|
330
337
|
@scheduler.schedule '0s' do
|
|
331
|
-
log(
|
|
338
|
+
log('Start-up, fetching is starting')
|
|
332
339
|
fetch_configuration_job_graphql
|
|
333
340
|
end
|
|
334
341
|
end
|
|
@@ -337,7 +344,7 @@ module Kameleoon
|
|
|
337
344
|
EM.synchrony do
|
|
338
345
|
obtain_access_token
|
|
339
346
|
@experiments = obtain_experiments_graphql(@site_code) || @experiments
|
|
340
|
-
@feature_flags = obtain_feature_flags_graphql(@site_code) || @feature_flags
|
|
347
|
+
@feature_flags = obtain_feature_flags_graphql(@site_code, @environment) || @feature_flags
|
|
341
348
|
EM.stop
|
|
342
349
|
end
|
|
343
350
|
end
|
|
@@ -479,9 +486,9 @@ module Kameleoon
|
|
|
479
486
|
experiments
|
|
480
487
|
end
|
|
481
488
|
|
|
482
|
-
def obtain_feature_flags_graphql(site_id, per_page = -1)
|
|
489
|
+
def obtain_feature_flags_graphql(site_id, environment = @environment, per_page = -1)
|
|
483
490
|
log "Fetching feature flags GraphQL"
|
|
484
|
-
feature_flags = fetch_all_graphql("v1/graphql?perPage=#{per_page}", Kameleoon::Query.query_feature_flags(site_code)).map { |it| JSON.parse(it.response)['data']['featureFlags']['edges'] }.flatten.map do |feature_flag|
|
|
491
|
+
feature_flags = fetch_all_graphql("v1/graphql?perPage=#{per_page}", Kameleoon::Query.query_feature_flags(site_code, environment)).map { |it| JSON.parse(it.response)['data']['featureFlags']['edges'] }.flatten.map do |feature_flag|
|
|
485
492
|
complete_campaign_graphql(feature_flag['node'])
|
|
486
493
|
end
|
|
487
494
|
log "Feature flags are fetched: " + feature_flags.inspect
|
|
@@ -580,6 +587,8 @@ module Kameleoon
|
|
|
580
587
|
feature_flag = @feature_flags.select { |ff| ff['identificationKey'] == feature_key}.first
|
|
581
588
|
elsif feature_key.is_a?(Integer)
|
|
582
589
|
feature_flag = @feature_flags.select { |ff| ff['id'].to_i == feature_key}.first
|
|
590
|
+
print "\nPassing `feature_key` with type of `int` to `activate_feature` or `obtain_feature_variable` "\
|
|
591
|
+
"is deprecated, it will be removed in next releases. This is necessary to support multi-environment feature\n"
|
|
583
592
|
else
|
|
584
593
|
raise TypeError.new("Feature key should be a String or an Integer.")
|
|
585
594
|
end
|
|
@@ -671,6 +680,12 @@ module Kameleoon
|
|
|
671
680
|
end
|
|
672
681
|
end
|
|
673
682
|
|
|
683
|
+
def check_site_code_enable(exp_or_ff)
|
|
684
|
+
unless exp_or_ff['site'].nil? || exp_or_ff['site']['isKameleoonEnabled']
|
|
685
|
+
raise Exception::SiteCodeDisabled.new(site_code)
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
|
|
674
689
|
def data_not_sent(visitor_code = nil)
|
|
675
690
|
if visitor_code.nil?
|
|
676
691
|
@data.select {|key, values| values.any? {|data| !data.sent}}
|
data/lib/kameleoon/exceptions.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Kameleoon
|
|
|
4
4
|
def self.query_experiments(site_code)
|
|
5
5
|
'{
|
|
6
6
|
"operationName": "getExperiments",
|
|
7
|
-
"query": "query getExperiments($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { experiments(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name type site { id code } status variations { id customJson } deviations { variationId value } respoolTime {variationId value } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
|
|
7
|
+
"query": "query getExperiments($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { experiments(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name type site { id code isKameleoonEnabled } status variations { id customJson } deviations { variationId value } respoolTime {variationId value } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
|
|
8
8
|
"variables": {
|
|
9
9
|
"filter": {
|
|
10
10
|
"and": [{
|
|
@@ -13,13 +13,15 @@ module Kameleoon
|
|
|
13
13
|
"operator": "IN",
|
|
14
14
|
"parameters": ["ACTIVE", "DEVIATED", "USED_AS_PERSONALIZATION"]
|
|
15
15
|
}
|
|
16
|
-
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
17
18
|
"condition": {
|
|
18
19
|
"field": "type",
|
|
19
20
|
"operator": "IN",
|
|
20
21
|
"parameters": ["SERVER_SIDE", "HYBRID"]
|
|
21
22
|
}
|
|
22
|
-
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
23
25
|
"condition": {
|
|
24
26
|
"field": "siteCode",
|
|
25
27
|
"operator": "IN",
|
|
@@ -35,10 +37,10 @@ module Kameleoon
|
|
|
35
37
|
}'
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
def self.query_feature_flags(site_code)
|
|
40
|
+
def self.query_feature_flags(site_code, environment)
|
|
39
41
|
'{
|
|
40
42
|
"operationName": "getFeatureFlags",
|
|
41
|
-
"query": "query getFeatureFlags($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { featureFlags(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name site { id code } bypassDeviation status variations { id customJson } respoolTime { variationId value } expositionRate identificationKey featureFlagSdkLanguageType featureStatus schedules { dateStart dateEnd } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
|
|
43
|
+
"query": "query getFeatureFlags($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { featureFlags(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name site { id code isKameleoonEnabled } bypassDeviation status variations { id customJson } respoolTime { variationId value } expositionRate identificationKey featureFlagSdkLanguageType featureStatus schedules { dateStart dateEnd } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
|
|
42
44
|
"variables": {
|
|
43
45
|
"filter": {
|
|
44
46
|
"and": [{
|
|
@@ -47,13 +49,21 @@ module Kameleoon
|
|
|
47
49
|
"operator": "IN",
|
|
48
50
|
"parameters": ["ACTIVATED", "SCHEDULED", "DEACTIVATED"]
|
|
49
51
|
}
|
|
50
|
-
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
51
54
|
"condition": {
|
|
52
55
|
"field": "siteCode",
|
|
53
56
|
"operator": "IN",
|
|
54
57
|
"parameters": ["' + site_code + '"]
|
|
55
58
|
}
|
|
56
|
-
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"condition": {
|
|
62
|
+
"field": "environment.key",
|
|
63
|
+
"operator": "IN",
|
|
64
|
+
"parameters": ["' + environment + '"]
|
|
65
|
+
}
|
|
66
|
+
}]
|
|
57
67
|
},
|
|
58
68
|
"sort": [{
|
|
59
69
|
"field": "id",
|
|
@@ -34,7 +34,7 @@ module Kameleoon
|
|
|
34
34
|
|
|
35
35
|
def check(datas)
|
|
36
36
|
is_targeted = false
|
|
37
|
-
custom_data = datas.select { |data| data.instance == DataType::CUSTOM && data.id == @index }.
|
|
37
|
+
custom_data = datas.select { |data| data.instance == DataType::CUSTOM && data.id == @index }.last
|
|
38
38
|
if custom_data.nil?
|
|
39
39
|
is_targeted = (@operator == Operator::UNDEFINED.to_s)
|
|
40
40
|
else
|
data/lib/kameleoon/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kameleoon-client-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kameleoon
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: em-http-request
|