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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +33 -0
- data/LICENSE +20 -0
- data/README.md +237 -0
- data/ige_isb_api.gemspec +29 -0
- data/lib/ige_isb_api.rb +49 -0
- data/lib/ige_isb_api/api.rb +251 -0
- data/lib/ige_isb_api/bonus.rb +249 -0
- data/lib/ige_isb_api/bonus_api.rb +125 -0
- data/lib/ige_isb_api/callback.rb +83 -0
- data/lib/ige_isb_api/constants.rb +284 -0
- data/lib/ige_isb_api/games.rb +433 -0
- data/lib/ige_isb_api/request.rb +164 -0
- data/lib/ige_isb_api/user_api.rb +251 -0
- data/lib/ige_isb_api/validation.rb +130 -0
- data/lib/ige_isb_api/version.rb +6 -0
- metadata +130 -0
@@ -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¶m2=value2¶m3=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
|