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: 887e6709dff33fa410a8e34a32577d8ad1ffe56fa52cadd24bd1734c68d2e46b
4
- data.tar.gz: e42d4d944e8c1549eae488f74e7b5c8891bf41f35dcce02133bfc68cee969463
3
+ metadata.gz: b70d1fc8cd47248dd68ba217e9a860577008e008cac7e6f562ab1856b3dc24c3
4
+ data.tar.gz: 03ddd4ce4f1ea480bc5adfc347c9f2168af952cc9036ce5cff494af9699a4dfe
5
5
  SHA512:
6
- metadata.gz: 3cf8ee8561091145b530082e2ce86614b41f9c63c70b644518c5a9d3738e659084526003ad298cdf320da0570cc7d55b551b3b80e680877a1c4c0bd984bc1b9f
7
- data.tar.gz: 4c9e4873467d1f2578be20f8246a47ad3810401251fb9e3dd34d3baad073184c6083fa0a35893c95e308a3482ebb3b42d58e1fd8e82c9400fa554ebbd1e16d63
6
+ metadata.gz: d3d39ad2e27a0312ff090f58a93cba6aa69450fd7763fbdc1375bd146bf1af909dde84815073fc7cf7d60b8aa123cb4cc139e8dee19c30aba3a88ae021475633
7
+ data.tar.gz: bfb92b7c42f02fde8d90484efef51abe294eaece630e97e7d0168e7974dd89d06b9069e9226c23bc2cf25755a2c1d4e41c87d114a1093b6e391a04d440f60de7
@@ -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 <= feature_flag['expositionRate']
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
- API_SSX_URL = "https://api-ssx.kameleoon.com"
322
+
323
+ API_SSX_URL = 'https://api-ssx.kameleoon.com'
318
324
  REFERENCE = 0
319
- STATUS_ACTIVE = "ACTIVE"
320
- FEATURE_STATUS_DEACTIVATED = "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("Scheduled job to fetch configuration is starting.")
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("Start-up, fetching is starting")
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}}
@@ -50,5 +50,10 @@ module Kameleoon
50
50
  super("Visitor code not valid: " + message)
51
51
  end
52
52
  end
53
+ class SiteCodeDisabled < KameleoonError
54
+ def initialize(message = "")
55
+ super("Site with siteCode '" + message + "' is disabled")
56
+ end
57
+ end
53
58
  end
54
59
  end
@@ -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 }.first
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
@@ -1,3 +1,3 @@
1
1
  module Kameleoon
2
- VERSION = '1.0.9'
2
+ VERSION = '1.0.10'
3
3
  end
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.9
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: 2021-11-25 00:00:00.000000000 Z
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