ige_isb_api 1.0.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,249 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "net/http"
5
+ require "uri"
6
+ require 'cgi'
7
+ require 'date'
8
+ require "ige_isb_api"
9
+ require "ige_isb_api/constants"
10
+
11
+ module IGE_ISB_API
12
+ class Bonus
13
+ attr_accessor :command, :params, :request
14
+
15
+ DEFAULT_PARAMS = {
16
+ 'api_key' => IGE_ISB_API::Constants::BONUS_API_KEY
17
+ }
18
+
19
+ COMMON_FIELDS = {
20
+ 'api_key' => {:required => true, :type => 'string', :length => 128}
21
+ }
22
+
23
+ COMMANDS = {
24
+ 'get_trigger_bonus' => {
25
+ 'login' => {:required => true, :type => 'username', :length => 32},
26
+ 'trigger' => {required: true, type: 'string', values: ['sign up', 'deposit', 'promotion code']},
27
+ 'transaction_ref' => {required: false, type: 'string', length: 128}
28
+ },
29
+ 'get_client_bonuses' => {
30
+ 'login' => {:required => true, :type => 'username', :length => 32},
31
+ 'statuses' => {required: false, type: 'string',
32
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_STATUSES},
33
+ 'types' => {required: false, type: 'string',
34
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_TYPES},
35
+ 'cartecs' => {required: false, type: 'string', length: 255},
36
+ 'start_date' => {required: false, type: 'date'},
37
+ 'end_date' => {required: false, type: 'date'},
38
+ 'start' => {required: false, type: 'int'},
39
+ 'results_per_page' => {required: false, type: 'int'},
40
+ 'order_by_field' => {required: false, type: 'string', values: [
41
+ 'cartec', 'bonus_initial_value', 'bonus_current_value', 'bonus_state',
42
+ 'bonus_type', 'issue_date', 'expiration_date', 'bonus_finish_date',
43
+ 'issued_by', 'total_bet', 'name'
44
+ ]},
45
+ 'order_by_dir' => {required: false, type: 'string', values: ['ASC', 'DESC']},
46
+ 'include_expired' => {required: false, type: 'boolint'},
47
+ 'only_expired' => {required: false, type: 'boolint'}
48
+ },
49
+ 'count_client_bonuses' => {
50
+ 'login' => {required: true, type: 'username'},
51
+ 'statuses' => {required: false, type: 'string',
52
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_STATUSES},
53
+ 'types' => {required: false, type: 'string',
54
+ values: IGE_ISB_API::Constants::ALLOWED_BONUS_TYPES},
55
+ 'cartecs' => {required: false, type: 'string', length: 255},
56
+ 'start_date' => {required: false, type: 'date'},
57
+ 'end_date' => {required: false, type: 'date'},
58
+ 'include_expired' => {required: false, type: 'boolint'},
59
+ 'only_expired' => {required: false, type: 'boolint'}
60
+ },
61
+ 'has_pending_offers' => {
62
+ 'login' => {required: true, type: 'username'},
63
+ },
64
+ 'accept_bonus' => {
65
+ 'login' => {required: true, type: 'username'},
66
+ 'id' => {required: true, type: 'int'}
67
+ },
68
+ 'decline_bonus' => {
69
+ 'login' => {required: true, type: 'username'},
70
+ 'id' => {required: true, type: 'int'}
71
+ },
72
+ 'get_remaining_playthrough' => {
73
+ 'login' => {required: true, type: 'username'}
74
+ },
75
+ 'remove_bonus_and_winnings_on_withdraw' => {
76
+ 'login' => {required: true, type: 'username'}
77
+ },
78
+ 'issue_bonus' => {
79
+ 'login' => {required: true, type: 'username'},
80
+ 'id_template' => {required: false, type: 'int'},
81
+ 'amount' => {required: false, type: 'currency'},
82
+ 'deposit_number' => {required: false, type: 'int'},
83
+ 'transaction_ref' => {required: false, type: 'string'},
84
+ 'transaction_type' => {required: false, type: 'string'},
85
+ 'transaction_date' => {required: false, type: 'timestamp'},
86
+ 'promo' => {required: false, type: 'string'},
87
+ 'location' => {required: false, type: 'string', values: ['cert', 'certd']}
88
+ },
89
+ 'cancel_bonus' => {
90
+ 'login' => {required: true, type: 'username'},
91
+ 'id_template' => {required: false, type: 'int'},
92
+ 'comment' => {required: false, type: 'string'}
93
+ },
94
+ 'reset_bonus' => {
95
+ 'login' => {required: true, type: 'username'}
96
+ },
97
+ 'update_active_balance_current_value' => {
98
+ 'login' => {required: true, type: 'username'},
99
+ 'deposit' => {required: true, type: 'currency'}
100
+ },
101
+ 'assign_certificate_to_player' => {
102
+ 'email' => {required: true, type: 'email', length: 50},
103
+ 'certificate_name' => {required: true, type: 'string'}
104
+ },
105
+ 'bonus_vip_points' => {
106
+ 'login' => {required: true, type: 'username'},
107
+ 'amount' => {required: true, type: 'currency'},
108
+ 'reason' => {required: false, type: 'string'},
109
+ 'name' => {required: true, type: 'string'}
110
+ },
111
+ 'generate_certificate' => {
112
+ 'template_certificate_id' => {required: true, type: 'int'}
113
+ },
114
+ 'generate_player_assigned_certificate' => {
115
+ 'login' => {required: true, type: 'username'},
116
+ 'template_certificate_id' => {required: true, type: 'int'}
117
+ },
118
+ 'get_template_id_by_name' => {
119
+ 'name' => {required: true, type: 'string'}
120
+ },
121
+ 'count_promo_codes' => {
122
+ 'login' => {required: true, type: 'username'},
123
+ 'start_date' => {required: true, type: 'timestamp'},
124
+ 'end_date' => {required: true, type: 'timestamp'}
125
+ },
126
+ 'sum_bonuses' => {
127
+ 'login' => {required: true, type: 'username'},
128
+ 'casino_prefix' => {required: false, type: 'string'}
129
+ },
130
+ 'is_transaction_used' => {
131
+ 'login' => {required: true, type: 'username'},
132
+ 'transaction' => {required: true, type: 'string'}
133
+ },
134
+ 'get_player_assigned_certificates' => {
135
+ 'login' => {required: true, type: 'username'},
136
+ 'promotion_code' => {required: false, type: 'string'},
137
+ 'template_certificate_ids' => {required: false, type: 'string'},
138
+ 'start_date' => {required: false, type: 'date'},
139
+ 'end_date' => {required: false, type: 'date'}
140
+ },
141
+ 'delete_player_assigned_certificate' => {
142
+ 'login' => {required: true, type: 'username'},
143
+ 'promotion_code' => {required: true, type: 'string'}
144
+ },
145
+ 'delete_generated_certificate' => {
146
+ 'promotion_code' => {required: true, type: 'string'}
147
+ },
148
+ 'certificate_exists' => {
149
+ 'promotion_code' => {required: true, type: 'string'}
150
+ }
151
+ }
152
+
153
+ def initialize(command, params = {})
154
+ self.command = command
155
+ self.params = self.class::DEFAULT_PARAMS.merge(self.convert_symbols_to_strings(params))
156
+ self.validate_parameters
157
+ # a bunch of stuff
158
+ self.sign
159
+ self.construct_request
160
+ end
161
+
162
+ def send
163
+ uri = URI.parse(IGE_ISB_API::Constants::BONUS_API_SERVER)
164
+ http = Net::HTTP.new(uri.host, uri.port)
165
+ # see http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
166
+ # http.use_ssl = true
167
+ # http.cert = OpenSSL::X509::Certificate.new(pem)
168
+ # http.key = OpenSSL::PKey::RSA.new(pem)
169
+ # http.verify_mode = OpenSSL::SSL::VERIFY_PEER
170
+ return http.request(self.request)
171
+ end
172
+
173
+ protected
174
+
175
+ # hash generated through the HMAC method using the sha256 algorithm with a private md5 key provided by ISB.
176
+ # The hash has to be made up of the url encoded query string, excluding the api_key
177
+ # Example: hash_hmac(“sha256”,urlencode(“param1=value1&param2=value2&param3=value3”),”private_key”)
178
+ def sign
179
+ return unless self.params['signature'].nil?
180
+ encoded_params = self.params.map { |key, value| "#{key}=#{value}" }
181
+ encoded_params.shift # remove the first item which is always the 'api_key'
182
+ hmac = Digest::HMAC.new(IGE_ISB_API::Constants::BONUS_SECRET_KEY, Digest::SHA256)
183
+ hmac << CGI.escape(encoded_params.join('&'))
184
+ self.params['signature'] = hmac.to_s
185
+ # puts "debugging params: api_key=#{self.params['api_key']}&#{encoded_params.join('&')}&signature=#{hmac.to_s}"
186
+ end
187
+
188
+ def convert_symbols_to_strings(a_hash = {})
189
+ return {} if a_hash.empty?
190
+ result = {}
191
+ a_hash.each {|key, value| result[key.to_s] = value }
192
+ return result
193
+ end
194
+
195
+ def validate_parameters
196
+ comfields = self.class::COMMANDS[self.command]
197
+ raise ValidationException, "Invalid command #{command}." if comfields.nil?
198
+ fields = self.class::COMMON_FIELDS.merge(comfields)
199
+ self.validate_fields(fields)
200
+ self.validate_no_extra_fields(fields)
201
+ end
202
+
203
+ def validate_fields(against)
204
+ against.each do |name, meta|
205
+ required = (meta[:required] === true)
206
+ # Check that all required parameters are present
207
+ if required && !self.params.keys.include?(name)
208
+ raise ValidationException, "Parameter #{name} is required, but missing from #{self.params.keys}"
209
+ end
210
+ if self.params.keys.include? name
211
+ p = self.params[name]
212
+ if p != nil
213
+ case meta[:type]
214
+ when 'timestamp'
215
+ self.params[name] = p = p.to_time.utc.to_i if p.is_a? Date
216
+ self.params[name] = p = p.utc.to_i if p.is_a?(Time)
217
+ self.params[name] = p = p.to_i if p.is_a?(String)
218
+ when 'currency'
219
+ p = p.to_f if p.is_a? String
220
+ if (p.is_a?(Float) || p.is_a?(Integer)) && p > 0
221
+ self.params[name] = p = "%.2f" % p
222
+ end
223
+ end
224
+ opts = {}
225
+ opts[:length] = meta[:length] if meta[:length]
226
+ opts[:values] = meta[:values] if meta[:values]
227
+ IGE_ISB_API::Validation.test name, self.params[name], meta[:type], opts
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ def validate_no_extra_fields(against)
234
+ allowed_fields = against.keys
235
+ self.params.each do |key, value|
236
+ raise InternalException, "Field #{key} is not supported" if !allowed_fields.include?(key)
237
+ end
238
+ end
239
+
240
+ def construct_request
241
+ raise RuntimeError, "Missing environment variable 'ISOFTBET_BONUS_API_SERVER'" if IGE_ISB_API::Constants::BONUS_API_SERVER.nil?
242
+ uri = URI.parse("#{IGE_ISB_API::Constants::BONUS_API_SERVER}/bonus_system/api/#{self.command}")
243
+ # http = Net::HTTP.new(uri.host, uri.port)
244
+ self.request = Net::HTTP::Post.new(uri)
245
+ self.request.set_form_data(self.params)
246
+ end
247
+
248
+ end
249
+ end
@@ -0,0 +1,125 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ module IGE_ISB_API
5
+ class BonusAPI
6
+
7
+ def initialize()
8
+ # nothing to do here right now.
9
+ end
10
+
11
+ # the following options *must* be passed in.
12
+ # trigger: one of 'sign up', 'deposit', or 'promotion code'
13
+ # login: "the user's username, as registered with ISB",
14
+ #
15
+ # The following may be passed in and are presented here with their defaults.
16
+ # transaction_ref: some unique transaction reference,
17
+ def get_trigger_bonus(opts = {})
18
+ return get_response_for __method__.to_s, opts
19
+ end
20
+
21
+ def get_client_bonuses(opts = {})
22
+ return get_response_for __method__.to_s, opts
23
+ end
24
+
25
+ def count_client_bonuses(opts = {})
26
+ return get_response_for __method__.to_s, opts
27
+ end
28
+
29
+ def has_pending_offers(opts = {})
30
+ return get_response_for __method__.to_s, opts
31
+ end
32
+
33
+ def accept_bonus(opts = {})
34
+ return get_response_for __method__.to_s, opts
35
+ end
36
+
37
+ def decline_bonus(opts = {})
38
+ return get_response_for __method__.to_s, opts
39
+ end
40
+
41
+ def get_remaining_playthrough(opts = {})
42
+ return get_response_for __method__.to_s, opts
43
+ end
44
+
45
+ def remove_bonus_and_winnings_on_withdraw(opts = {})
46
+ return get_response_for __method__.to_s, opts
47
+ end
48
+
49
+ def issue_bonus(opts = {})
50
+ return get_response_for __method__.to_s, opts
51
+ end
52
+
53
+ def cancel_bonus(opts = {})
54
+ return get_response_for __method__.to_s, opts
55
+ end
56
+
57
+ def reset_bonus(opts = {})
58
+ return get_response_for __method__.to_s, opts
59
+ end
60
+
61
+ def update_active_balance_current_value(opts = {})
62
+ return get_response_for __method__.to_s, opts
63
+ end
64
+
65
+ def assign_certificate_to_player(opts = {})
66
+ return get_response_for __method__.to_s, opts
67
+ end
68
+
69
+ def bonus_vip_points(opts = {})
70
+ return get_response_for __method__.to_s, opts
71
+ end
72
+
73
+ def generate_certificate(opts = {})
74
+ return get_response_for __method__.to_s, opts
75
+ end
76
+
77
+ def generate_player_assigned_certificate(opts = {})
78
+ return get_response_for __method__.to_s, opts
79
+ end
80
+
81
+ def get_template_id_by_name(opts = {})
82
+ return get_response_for __method__.to_s, opts
83
+ end
84
+
85
+ def count_promo_codes(opts = {})
86
+ return get_response_for __method__.to_s, opts
87
+ end
88
+
89
+ def sum_bonuses(opts = {})
90
+ return get_response_for __method__.to_s, opts
91
+ end
92
+
93
+ def is_transaction_used(opts = {})
94
+ return get_response_for __method__.to_s, opts
95
+ end
96
+
97
+ def get_player_assigned_certificates(opts = {})
98
+ return get_response_for __method__.to_s, opts
99
+ end
100
+
101
+ def delete_player_assigned_certificate(opts = {})
102
+ return get_response_for __method__.to_s, opts
103
+ end
104
+
105
+ def delete_generated_certificate(opts = {})
106
+ return get_response_for __method__.to_s, opts
107
+ end
108
+
109
+ def certificate_exists(opts = {})
110
+ return get_response_for __method__.to_s, opts
111
+ end
112
+
113
+ protected
114
+
115
+ def get_response_for(a_command, opts = {})
116
+ # puts "got command #{a_command} with options #{opts}"
117
+ raise ArgumentError, "Missing options." if opts.empty?
118
+ bonus_request = IGE_ISB_API::Bonus.new a_command, opts
119
+ resp = bonus_request.send
120
+ response = JSON.parse(resp.body)
121
+ return response
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,83 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+ require 'digest'
4
+
5
+ module IGE_ISB_API
6
+ class Callback
7
+
8
+ # {
9
+ # "player": String # player login as originally passed to ISB at .registration,
10
+ # "requestid":Integer, # same as we provided in the IDREQUEST field
11
+ # "token": String - # a SHA2 digest of our 'SECRETKEY' + 'IDREQUEST' which we will use to authenticate the incoming info.,
12
+ # "sesson-start":"2013/10/25.10:54:18",
13
+ # "sesson-end":"2013/10/25.12:32:51",
14
+ # "skin_ID": 2019
15
+ # "currency":"USD",
16
+ # "hostID":1,
17
+ # "actions":[
18
+ # {
19
+ # "bet":{
20
+ # "amount": 1.00
21
+ # },
22
+ # "bet":{
23
+ # "amount": 50.00
24
+ # },
25
+ # "win":{
26
+ # "amount": 80.00
27
+ # }
28
+ # }
29
+ # ]
30
+ # }
31
+ def self.parse(raw_data)
32
+ raise ValidationException, "No data to parse" if raw_data.nil? || raw_data.empty?
33
+ begin
34
+ data = JSON.parse(raw_data)
35
+ player = data['player']
36
+ IGE_ISB_API::Validation.test('player', player, 'username')
37
+ requestid = data['requestid'].to_i
38
+ IGE_ISB_API::Validation.test('requestid', requestid, 'int')
39
+ token = data['token']
40
+ expected = (Digest::SHA2.new << "#{IGE_ISB_API::Constants::SECRET_KEY}#{requestid}").to_s
41
+ raise ValidationException, "Invalid Token" unless token == expected
42
+ session_start = DateTime.strptime(data['session-start'], "%Y/%m/%d.%H:%M:%S").to_time.utc
43
+ session_end = DateTime.strptime(data['session-end'], "%Y/%m/%d.%H:%M:%S").to_time.utc
44
+ raise ValidationException, "session-end must be after session-start" unless session_start < session_end
45
+ skinid = data['skin_ID'].to_i
46
+ IGE_ISB_API::Validation.test('skin_ID', skinid, 'int')
47
+ currency = data['currency']
48
+ IGE_ISB_API::Validation.test('currency', currency, 'currency_code')
49
+ hostid = data['hostID'].to_i
50
+ actions = data['actions'].map do |act|
51
+ if act['bet']
52
+ {
53
+ action: :bet,
54
+ amount: act['bet']['amount'].to_f
55
+ }
56
+ elsif act['win']
57
+ {
58
+ action: :win,
59
+ amount: act['win']['amount'].to_f
60
+ }
61
+ else
62
+ raise ValidationException, "Invalid Action"
63
+ end
64
+ end
65
+ return {
66
+ player: player,
67
+ requestid: requestid,
68
+ session_start: session_start,
69
+ session_end: session_end,
70
+ skinid: skinid,
71
+ currency: currency,
72
+ hostid: hostid,
73
+ actions: actions
74
+ }
75
+ rescue ArgumentError => ae
76
+ raise ValidationException, ae.message
77
+ rescue JSON::ParserError => jpe
78
+ raise ValidationException, "Invalid JSON format in supplied data: #{jpe.message}"
79
+ end
80
+ end
81
+
82
+ end
83
+ end