vwo-sdk 1.3.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.
@@ -0,0 +1,102 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require 'json'
18
+
19
+ class VWO
20
+ # Schema for verifying the settings_file provided by the customer
21
+ module Schema
22
+ SETTINGS_FILE_SCHEMA = {
23
+ type: 'object',
24
+ properties: {
25
+ version: {
26
+ type: %w[number string]
27
+ },
28
+ accountId: {
29
+ type: %w[number string]
30
+ },
31
+ campaigns: {
32
+ if: {
33
+ type: 'array'
34
+ },
35
+ then: {
36
+ minItems: 1,
37
+ items: {
38
+ '$ref' => '#/definitions/campaign_object_schema'
39
+ }
40
+ },
41
+ else: {
42
+ type: 'object',
43
+ maxProperties: 0
44
+ }
45
+ }
46
+ },
47
+ definitions: {
48
+ campaign_variation_schema: {
49
+ type: 'object',
50
+ properties: {
51
+ id: {
52
+ type: %w[number string]
53
+ },
54
+ name: {
55
+ type: ['string']
56
+ },
57
+ weight: {
58
+ type: %w[number string]
59
+ }
60
+ },
61
+ required: %w[id name weight]
62
+ },
63
+ campaign_object_schema: {
64
+ type: 'object',
65
+ properties: {
66
+ id: {
67
+ type: %w[number string]
68
+ },
69
+ key: {
70
+ type: ['string']
71
+ },
72
+ status: {
73
+ type: ['string']
74
+ },
75
+ percentTraffic: {
76
+ type: ['number']
77
+ },
78
+ variations: {
79
+ type: 'array',
80
+ items: {
81
+ '$ref' => '#/definitions/campaign_variation_schema'
82
+ }
83
+ },
84
+ minItems: 2
85
+ }
86
+ },
87
+ required: %w[
88
+ id
89
+ key
90
+ status
91
+ percentTraffic
92
+ variations
93
+ ]
94
+ },
95
+ required: %w[
96
+ version
97
+ accountId
98
+ campaigns
99
+ ]
100
+ }.freeze
101
+ end
102
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative '../logger'
18
+ require_relative '../enums'
19
+ require_relative '../utils/request'
20
+
21
+ class VWO
22
+ module Services
23
+ class EventDispatcher
24
+ include VWO::Enums
25
+
26
+ EXCLUDE_KEYS = ['url'].freeze
27
+
28
+ # Initialize the dispatcher with logger and development mode
29
+ #
30
+ # @param [Boolean] : To specify whether the request
31
+ # to our server should be made or not.
32
+ #
33
+ def initialize(is_development_mode = false)
34
+ @logger = VWO::Logger.get_instance
35
+ @is_development_mode = is_development_mode
36
+ end
37
+
38
+ # Dispatch the impression event having properties object only if dev-mode is OFF
39
+ #
40
+ # @param[Hash] :properties hash having impression properties
41
+ # the request to be dispatched to the VWO server
42
+ # @return[Boolean]
43
+ #
44
+ def dispatch(impression)
45
+ return true if @is_development_mode
46
+
47
+ modified_event = impression.reject do |key, _value|
48
+ EXCLUDE_KEYS.include?(key)
49
+ end
50
+
51
+ resp = VWO::Utils::Request.get(impression['url'], modified_event)
52
+ if resp.code == '200'
53
+ @logger.log(
54
+ LogLevelEnum::INFO,
55
+ format(
56
+ LogMessageEnum::InfoMessages::IMPRESSION_SUCCESS,
57
+ file: FileNameEnum::EventDispatcher,
58
+ end_point: impression[:url],
59
+ campaign_id: impression[:experiment_id],
60
+ user_id: impression[:uId],
61
+ account_id: impression[:account_id],
62
+ variation_id: impression[:combination]
63
+ )
64
+ )
65
+ return true
66
+ else
67
+ @logger.log(
68
+ LogLevelEnum::ERROR,
69
+ format(LogMessageEnum::ErrorMessages::IMPRESSION_FAILED, file: FileNameEnum::EventDispatcher, end_point: impression['url'])
70
+ )
71
+ return false
72
+ end
73
+ rescue StandardError
74
+ @logger.log(
75
+ LogLevelEnum::ERROR,
76
+ format(LogMessageEnum::ErrorMessages::IMPRESSION_FAILED, file: FileNameEnum::EventDispatcher, end_point: impression['url'])
77
+ )
78
+ false
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,84 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative '../utils/function'
18
+ require_relative '../utils/request'
19
+ require_relative '../utils/validations'
20
+ require_relative '../constants'
21
+
22
+ class VWO
23
+ module Services
24
+ class SettingsFileManager
25
+ include ::VWO::Utils::Validations
26
+ include ::VWO::Utils::Function
27
+
28
+ PROTOCOL = 'https'
29
+ HOSTNAME = ::VWO::CONSTANTS::ENDPOINTS::BASE_URL
30
+ PATH = ::VWO::CONSTANTS::ENDPOINTS::ACCOUNT_SETTINGS
31
+
32
+ def initialize(account_id, sdk_key)
33
+ @account_id = account_id
34
+ @sdk_key = sdk_key
35
+ end
36
+
37
+ # Get Settings file method to retrieve settings_file for customer from VWO server
38
+ # @param [string]: Account ID of user
39
+ # @param [string]: Unique sdk key for user,
40
+ # can be retrieved from VWO app
41
+ # @return[string]: JSON - settings_file,
42
+ # as received from the server,
43
+ # nil if no settings_file is found or sdk_key is incorrect
44
+
45
+ def get_settings_file
46
+ is_valid_key = valid_number?(@account_id) || valid_string?(@account_id)
47
+
48
+ unless is_valid_key && valid_string?(@sdk_key)
49
+ STDERR.puts 'account_id and sdk_key are required for fetching account settings. Aborting!'
50
+ return '{}'
51
+ end
52
+
53
+ vwo_server_url = "#{PROTOCOL}://#{HOSTNAME}#{PATH}"
54
+
55
+ settings_file_response = ::VWO::Utils::Request.get(vwo_server_url, params)
56
+
57
+ if settings_file_response.code != '200'
58
+ message = <<-DOC
59
+ Request failed for fetching account settings.
60
+ Got Status Code: #{settings_file_response.code}
61
+ and message: #{settings_file_response.body}.
62
+ DOC
63
+ STDERR.puts message
64
+ return
65
+ end
66
+ settings_file_response.body
67
+ rescue StandardError => e
68
+ STDERR.puts "Error fetching Settings File #{e}"
69
+ end
70
+
71
+ private
72
+
73
+ def params
74
+ {
75
+ a: @account_id,
76
+ i: @sdk_key,
77
+ r: get_random_number,
78
+ platform: 'server',
79
+ 'api-version' => 1
80
+ }
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative '../logger'
18
+ require_relative '../enums'
19
+ require_relative '../utils/campaign'
20
+
21
+ class VWO
22
+ module Services
23
+ class SettingsFileProcessor
24
+ include VWO::Enums
25
+ include VWO::Utils::Campaign
26
+
27
+ # Method to initialize settings_file and logger
28
+ #
29
+ # @params
30
+ # settings_file (Hash): Hash object of setting
31
+ # representing the settings_file.
32
+
33
+ def initialize(settings_file)
34
+ @settings_file = JSON.parse(settings_file)
35
+ @logger = VWO::Logger.get_instance
36
+ end
37
+
38
+ # Processes the settings_file, assigns variation allocation range
39
+ def process_settings_file
40
+ (@settings_file['campaigns'] || []).each do |campaign|
41
+ set_variation_allocation(campaign)
42
+ end
43
+ @logger.log(
44
+ LogLevelEnum::DEBUG,
45
+ format(LogMessageEnum::DebugMessages::SETTINGS_FILE_PROCESSED, file: FileNameEnum::SettingsFileProcessor)
46
+ )
47
+ end
48
+
49
+ def get_settings_file
50
+ @settings_file
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ class VWO
18
+ # UserStorage Class is used to store user-variation mapping.
19
+ # Override this class to implement your own functionality.
20
+ # SDK will ensure to use this while bucketing a user into a variation.
21
+
22
+ class UserStorage
23
+ # To retrieve the stored variation for the user_id.
24
+ #
25
+ # @param[String] :user_id ID for user that needs to be retrieved.
26
+ # @param[String] :_campaign_key Unique campaign key
27
+ # @return[Hash] :user_data User's data.
28
+ #
29
+ def get(_user_id, _campaign_key); end
30
+
31
+ # To store the the user variation-mapping
32
+ # @param[Hash] :user_data
33
+ #
34
+ def set(_user_data); end
35
+ end
36
+ end
@@ -0,0 +1,125 @@
1
+ # Copyright 2019 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative '../logger'
18
+ require_relative '../enums'
19
+ require_relative '../constants'
20
+
21
+ # Utility module for processing VWO campaigns
22
+ class VWO
23
+ module Utils
24
+ module Campaign
25
+ include VWO::Enums
26
+ include VWO::CONSTANTS
27
+
28
+ # Finds and Returns campaign from given campaign_key.
29
+ #
30
+ # @param[Hash] :settings_file Settings file
31
+ # @param[String] :campaign_key Campaign identifier key
32
+ # @return[Hash] :campaign object
33
+
34
+ def get_campaign(settings_file, campaign_key)
35
+ (settings_file['campaigns'] || []).find do |campaign|
36
+ campaign['key'] == campaign_key
37
+ end
38
+ end
39
+
40
+ # Sets variation allocation range in the provided campaign
41
+ #
42
+ # @param [Hash]: Campaign object
43
+
44
+ def set_variation_allocation(campaign)
45
+ current_allocation = 0
46
+ campaign['variations'].each do |variation|
47
+ step_factor = get_variation_bucketing_range(variation['weight'])
48
+ if step_factor > 0
49
+ start_range = current_allocation + 1
50
+ end_range = current_allocation + step_factor
51
+ variation['start_variation_allocation'] = start_range
52
+ variation['end_variation_allocation'] = end_range
53
+ current_allocation += step_factor
54
+ else
55
+ variation['start_variation_allocation'] = -1
56
+ variation['end_variation_allocation'] = -1
57
+ end
58
+
59
+ VWO::Logger.get_instance.log(
60
+ LogLevelEnum::INFO,
61
+ format(
62
+ LogMessageEnum::InfoMessages::VARIATION_RANGE_ALLOCATION,
63
+ file: FileNameEnum::CampaignUtil,
64
+ campaign_key: campaign['key'],
65
+ variation_name: variation['name'],
66
+ variation_weight: variation['weight'],
67
+ start: variation['start_variation_allocation'],
68
+ end: variation['end_variation_allocation']
69
+ )
70
+ )
71
+ end
72
+ end
73
+
74
+ # Returns goal from given campaign_key and gaol_identifier.
75
+ # @param[Hash] :settings_file Settings file
76
+ # @param[String] :campaign_key Campaign identifier key
77
+ # @param[String] :goal_identifier Goal identifier
78
+ #
79
+ # @return[Hash] Goal corresponding to Goal_identifier in respective campaign
80
+
81
+ def get_campaign_goal(settings_file, campaign_key, goal_identifier)
82
+ return unless settings_file && campaign_key && goal_identifier
83
+
84
+ campaign = get_campaign(settings_file, campaign_key)
85
+ return unless campaign
86
+
87
+ campaign['goals'].find do |goal|
88
+ goal['identifier'] == goal_identifier
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ # Returns the bucket size of variation.
95
+ # @param (Number): weight of variation
96
+ # @return (Integer): Bucket start range of Variation
97
+
98
+ def get_variation_bucketing_range(weight)
99
+ return 0 if weight.nil? || weight == 0
100
+
101
+ start_range = (weight * 100).ceil.to_i
102
+ [start_range, MAX_TRAFFIC_VALUE].min
103
+ end
104
+
105
+ # Returns variation from given campaign_key and variation_name.
106
+ #
107
+ # @param[Hash] :settings_file Settings file
108
+ # @param[Hash] :campaign_key Campaign identifier key
109
+ # @param[String] :variation_name Variation identifier
110
+ #
111
+ # @return[Hash] Variation corresponding to variation_name in respective campaign
112
+
113
+ def get_campaign_variation(settings_file, campaign_key, variation_name)
114
+ return unless settings_file && campaign_key && variation_name
115
+
116
+ campaign = get_campaign(settings_file, campaign_key)
117
+ return unless campaign
118
+
119
+ campaign['variations'].find do |variation|
120
+ variation['name'] == variation_name
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end