allorails 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,284 @@
1
+ require 'net/http'
2
+ require 'cgi'
3
+ require 'digest'
4
+
5
+ module Allorails
6
+ module Request
7
+
8
+ class ApiRequest
9
+
10
+ # API response format needed to provide response object mapping
11
+ MAPPING_FORMAT = 'json'
12
+ # API remote base path
13
+ API_PATH = '/rest'
14
+
15
+ ## Returns the remote path of the Allopass API service
16
+ #
17
+ # @return (string) A remote path
18
+ def _path
19
+ self.class::PATH
20
+ end
21
+
22
+ # class of the Response
23
+ ## Returns an object mapping the Allopass API response
24
+ #
25
+ # @param signature (string) Expected response signature
26
+ # @param headers (list) Response HTTP headers
27
+ # @param body (string) Raw response data
28
+ #
29
+ # @return ApiResponse An object mapping the Allopass API response
30
+ def _new_response(signature, headers, body)
31
+ raise "new_response is not implemented"
32
+ end
33
+
34
+ ## Constructor
35
+ #
36
+ # @param parameters (array) Parameters to the API call
37
+ # @param mapping (boolean) Wether to return a raw response or an object
38
+ # @param emailAccount (string) Configurated email account
39
+ def initialize(parameters, mapping = true, email_account = nil)
40
+ @_mapping = mapping
41
+ @_parameters = parameters
42
+ @_email_account = email_account
43
+ end
44
+
45
+ ## Call the Allopass API and returns the response (raw or object)
46
+ #
47
+ # @return ApiResponse The API response
48
+ def call()
49
+ headers, body = self._build_parameters._sign._call
50
+ signature = self._hash(body + Allorails.config.private_key(@_email_account))
51
+
52
+ if (@_mapping)
53
+ return self._new_response(signature, headers, body)
54
+ else
55
+ return Allorails::Response::ApiResponse.new(signature, headers, body)
56
+ end
57
+ end
58
+
59
+ ## Internal method building special required API parameters
60
+ #
61
+ # @return ApiRequest Class instance for chaining purpose
62
+ def _build_parameters
63
+ formats = ['json', 'xml']
64
+
65
+ @_parameters.update({
66
+ 'api_ts' => Time.now.to_i,
67
+ 'api_key' => Allorails.config.api_key(@_email_account),
68
+ 'api_hash' => Allorails.config.default_hash
69
+ })
70
+
71
+ if @_parameters.has_key?('format')
72
+ if (@_mapping)
73
+ @_parameters['format'] = self::MAPPING_FORMAT
74
+ elsif !formats.include?(@_parameters['format'])
75
+ @_parameters['format'] = Allorails.config.default_format
76
+ end
77
+ else
78
+ @_parameters['format'] = Allorails.config.default_format
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ ## Internal methods used to sign the request call
85
+ #
86
+ # @return ApiRequest Class instance for chaining purpose
87
+ def _sign
88
+ params = @_parameters.dup
89
+
90
+ if params.has_key?('code')
91
+ params['code'] = params['code'].join
92
+ end
93
+
94
+ sign = params.sort.map{|p| "#{p[0]}#{p[1]}"}.join
95
+ @_parameters['api_sig'] = self._hash(sign + Allorails.config.private_key(@_email_account))
96
+
97
+ self
98
+ end
99
+
100
+ ## Internal method hashing data with defined cipher #TODO en prenant en compte la donnée incrite dans les confs
101
+ #
102
+ # @parameter data (string) Data to hash
103
+ #
104
+ # @throws ApiMissingHashFeatureError If defined cipher method isn'h available
105
+ def _hash(data)
106
+ ::Digest::SHA1.hexdigest(data)
107
+ end
108
+
109
+ ## Internal method deciding wether to use a POST request
110
+ #
111
+ # @return (boolean) True to use POST
112
+ def _is_http_post
113
+ false
114
+ end
115
+
116
+ ## Internal method calling the Allopass API
117
+ #
118
+ # @return (tuple) Pair containing response headers and body
119
+ def _call
120
+ protocol = Allorails.config.network_protocol
121
+ server = Allorails.config.host
122
+ timeout = Allorails.config.network_timeout.to_f
123
+
124
+ port = protocol == 'https' ? 443 : 80
125
+ uri = URI(protocol + '://' + server + ApiRequest::API_PATH + _path)
126
+ method = _is_http_post ? 'POST' : 'GET'
127
+ headers = {
128
+ "Content-Type" => "application/x-www-form-urlencoded; charset=utf-8",
129
+ "User-Agent" => "Allopass-ApiKit-AlloRails"
130
+ }
131
+
132
+ # use a proxy?
133
+ use_proxy = false
134
+ http_class = if use_proxy then Net::HTTP::Proxy('127.0.0.1', 9999) else Net::HTTP end
135
+
136
+ # prepare and send HTTP request
137
+ http_class.start(uri.host, port, :use_ssl => uri.scheme == 'https') do |http|
138
+
139
+ if method == 'GET'
140
+ uri.query = _encode_parameters
141
+ req = http_class::Get.new uri.request_uri
142
+ else
143
+ #uri.query = _encode_parameters
144
+ req = http_class::Post.new uri.request_uri
145
+ req.body = _encode_parameters
146
+ end
147
+
148
+ # set headers
149
+ headers.each_pair{|k, v| req[k] = v}
150
+
151
+ # send the request and see if successful
152
+ case res = http.request(req)
153
+ when Net::HTTPSuccess then return [res.to_hash, res.body]
154
+ else raise Allorails::ApiUnavailableResourceError, "Request failed: #{res.body}"
155
+ end
156
+ end
157
+ end
158
+
159
+ ## Internal method encoding request paramters
160
+ #
161
+ # @return (string) Encoded request parameters
162
+ def _encode_parameters
163
+ params = @_parameters.dup
164
+ # The Allopass API expects an array of codes encoded
165
+ # in a slightly different matter than urlencode does
166
+ if params.has_key?('code')
167
+ codes = params.delete('code')
168
+ hash_codes = Hash[[0..codes.length-1].map{|i| ["code[#{i}]",codes[i]]}]
169
+ params = params.merge(hash_codes)
170
+ end
171
+
172
+ URI::encode params.collect { |k,v| "#{k}=#{v}" }.join('&') #CGI::escape(v.to_s)
173
+ end
174
+
175
+ end # -- end class ApiRequest
176
+
177
+
178
+ ## Class providing a onetime pricing API request
179
+ class OnetimePricingRequest < ApiRequest
180
+ PATH = '/onetime/pricing'
181
+
182
+ def _new_response(signature, headers, body)
183
+ Allorails::Response::OnetimePricingResponse.new(signature, headers, body)
184
+ end
185
+ end
186
+
187
+
188
+ ## Class providing a onetime dicrete pricing API request
189
+ class OnetimeDiscretePricingRequest < ApiRequest
190
+ PATH = '/onetime/discrete-pricing'
191
+
192
+ def _new_response(signature, headers, body)
193
+ Allorails::Response::OnetimePricingResponse.new(signature, headers, body)
194
+ end
195
+ end
196
+
197
+
198
+ ## Class providing a onetime validate codes API request
199
+ class OnetimeValidateCodesRequest < ApiRequest
200
+ PATH = '/onetime/validate-codes'
201
+
202
+ def _is_http_post
203
+ true
204
+ end
205
+
206
+ def _new_response(signature, headers, body)
207
+ Allorails::Response::OnetimeValidateCodesResponse.new(signature, headers, body)
208
+ end
209
+ end
210
+
211
+
212
+ ## Class providing a product detail API request
213
+ class ProductDetailRequest < ApiRequest
214
+ PATH = '/product'
215
+
216
+ def _new_response(signature, headers, body)
217
+ Allorails::Response::ProductDetailResponse.new(signature, headers, body)
218
+ end
219
+ end
220
+
221
+
222
+ ## Class providing a transaction prepare API request
223
+ class TransactionPrepareRequest < ApiRequest
224
+ PATH = '/transaction/prepare'
225
+
226
+ def _is_http_post
227
+ true
228
+ end
229
+
230
+ def _new_response(signature, headers, body)
231
+ Allorails::Response::TransactionPrepareResponse.new(signature, headers, body)
232
+ end
233
+ end
234
+
235
+
236
+ ## Class providing a transaction detail API request
237
+ class TransactionDetailRequest < ApiRequest
238
+ PATH = '/transaction'
239
+
240
+ def _new_response(signature, headers, body)
241
+ Allorails::Response::TransactionDetailResponse.new(signature, headers, body)
242
+ end
243
+ end
244
+
245
+
246
+ ## Class providing a transaction detail from merchant transaction id API request
247
+ class TransactionMerchantRequest < ApiRequest
248
+ PATH = '/transaction/merchant'
249
+
250
+ def _new_response(signature, headers, body)
251
+ Allorails::Response::TransactionDetailResponse.new(signature, headers, body)
252
+ end
253
+ end
254
+
255
+
256
+ ## Class providing a onetime button API request
257
+ class OnetimeButtonRequest < ApiRequest
258
+ PATH = '/onetime/button'
259
+
260
+ def _is_http_post
261
+ true
262
+ end
263
+
264
+ def _new_response(signature, headers, body)
265
+ Allorails::Response::OnetimeButtonResponse.new(signature, headers, body)
266
+ end
267
+ end
268
+
269
+
270
+ ## Class providing a onetime discrete button API request
271
+ class OnetimeDiscreteButtonRequest < ApiRequest
272
+ PATH = '/onetime/discrete-button'
273
+
274
+ def _is_http_post
275
+ true
276
+ end
277
+
278
+ def _new_response(signature, headers, body)
279
+ Allorails::Response::OnetimeButtonResponse.new(signature, headers, body)
280
+ end
281
+ end
282
+
283
+ end
284
+ end
@@ -0,0 +1,278 @@
1
+ module Allorails
2
+
3
+
4
+ ## Basis for the models used in the Apikit object responses
5
+ # extends ApiMappingResponse to inherit the node_reader helper
6
+ class Base < Allorails::Response::ApiMappingResponse
7
+
8
+ def initialize(node)
9
+ @json = node
10
+ end
11
+
12
+ end
13
+
14
+
15
+ ## Class providing object mapping of a website item
16
+ class Website < Base
17
+
18
+ ## Provides the website id
19
+ # @return (int) website id
20
+ node_reader :id, Integer
21
+
22
+ ## Provides the website name
23
+ # @return (string) website name
24
+ node_reader :name
25
+
26
+ ## Provides the website url
27
+ # @return (string) website url
28
+ node_reader :url
29
+
30
+ ## Checks wether the website's audience is restricted
31
+ # @return (boolean) wether the website's audience is restricted
32
+ def audience_restricted?
33
+ @json.audience_restricted == 'true'
34
+ end
35
+
36
+ ## Provides the website category
37
+ # @return (string) website category
38
+ node_reader :category
39
+
40
+ end
41
+
42
+
43
+ ## Class providing object mapping of a country item
44
+ class Country < Base
45
+
46
+ ## Provides the country code
47
+ # @return (string) country code (two characters)
48
+ node_reader :code
49
+
50
+ ## Provides the country name
51
+ # @return (string) country name
52
+ node_reader :name
53
+
54
+ end
55
+
56
+
57
+ ## Class providing object mapping of a region item
58
+ class Region < Base
59
+
60
+ ## Provides the region name
61
+ # @return (string) region name
62
+ node_reader :name
63
+
64
+ ## Provides the countries in the region
65
+ # @return (Array) region's countries
66
+ def countries
67
+ json.children.values.map{|c| ::Allorails::Country.new(c)}
68
+ end
69
+
70
+ end
71
+
72
+
73
+ ## Class providing object mapping of a market item
74
+ class Market < Base
75
+
76
+ ## Provides the country code
77
+ # @return (string) country code (two characters)
78
+ node_reader :country_code
79
+
80
+ ## Provides the country name
81
+ # @return (string) country name
82
+ node_reader :country
83
+
84
+ ## Provides the pricepoints available in this market
85
+ # @return (Array) available pricepoints (list of Pricepoint objects)
86
+ def pricepoints
87
+ json.children.values.map{|c| ::Allorails::Pricepoint.new(c)}
88
+ end
89
+
90
+ end
91
+
92
+
93
+ ## Class providing object mapping of a price item
94
+ class Price < Base
95
+
96
+ ## Provides the currency
97
+ # @return (string) currency (three characters)
98
+ node_reader :currency
99
+
100
+ ## Provides the amount
101
+ # @return (float) amount
102
+ node_reader :currency, Float
103
+
104
+ ## Provides the day's exchange rate
105
+ # @return (float) exchange rate
106
+ node_reader :exchange, Float
107
+
108
+ ## Provides the reference currency
109
+ # @return (string) reference currency
110
+ node_reader :reference_currency
111
+
112
+ ## Provides the amount in the reference currency
113
+ # @return (float) reference amount
114
+ node_reader :reference_amount, Float
115
+
116
+ end
117
+
118
+ ## Class providing object mapping of a payout item
119
+ class Payout < Base
120
+
121
+ ## Provides the currency
122
+ # @return (string) currency (three characters)
123
+ node_reader :currency
124
+
125
+ ## Provides the amount
126
+ # @return (float) amount
127
+ node_reader :amount, Float
128
+
129
+ ## Provides the day's exchange rate
130
+ # @return (float) exchange rate
131
+ node_reader :exchange, Float
132
+
133
+ ## Provides the reference currency
134
+ # @return (string) reference currency
135
+ node_reader :reference_currency
136
+
137
+ ## Provides the amount in the reference currency
138
+ # @return (float) reference amount
139
+ node_reader :reference_amount, Float
140
+
141
+ end
142
+
143
+
144
+ ## Class providing object mapping of a phone number item
145
+ class PhoneNumber < Base
146
+
147
+ ## Provides the phone number
148
+ # @return (string) phone number
149
+ node_reader :value
150
+
151
+ ## Provides the description of the phone number
152
+ # @return (string) description
153
+ node_reader :description
154
+
155
+ end
156
+
157
+
158
+ ## Class providing object mapping of a keyword item
159
+ class Keyword < Base
160
+
161
+ ## Provides the keyword name
162
+ # @return (string) keyword name
163
+ node_reader :name
164
+
165
+ ## Provides the keyword's shortcode
166
+ # @return (string) shortcode
167
+ node_reader :shortcode
168
+
169
+ ## Provides the keyword operators
170
+ # @return (string) keyword operators
171
+ node_reader :operators
172
+
173
+ ## Provides the number of billed messages of the keyword
174
+ # @return (int) number of billed messages
175
+ node_reader :number_billed_messages, Integer
176
+
177
+ ## Provides a description of the keyword
178
+ # @return (string) description
179
+ node_reader :description
180
+
181
+ end
182
+
183
+
184
+ ## Class providing object mapping of a pricepoint item
185
+ class Pricepoint < Base
186
+
187
+ ## Provides the pricepoint's id
188
+ # @return (int) pricepoint id
189
+ node_reader :id, Integer
190
+
191
+ ## Provides the pricepoint's type
192
+ # @return (string) pricepoint type
193
+ node_reader :type
194
+
195
+ ## Provides the pricepoint's country code
196
+ # @return (string) country code (two characters)
197
+ node_reader :country_code
198
+
199
+ ## Provides price information
200
+ # @return (Price) price information
201
+ node_reader :price, ::Allorails::Price
202
+
203
+ ## Provides the pricepoint's payout
204
+ # @return (Payout) pricepoint's payout
205
+ node_reader :payout, ::Allorails::Payout
206
+
207
+ ## Provides the buy url
208
+ # @return (string) buy url
209
+ node_reader :buy_url
210
+
211
+ ## Provides the pricepoint's phone numbers
212
+ # @return (list) pricepoint's phone number (list of PhoneNumber objects)
213
+ def phone_numbers
214
+ return nil if json.phone_numbers.nil?
215
+ json.phone_numbers.children.values.map{|c| ::Allorails::PhoneNumber(c)}
216
+ end
217
+
218
+ ## Provides the pricepoint's keywords
219
+ # @return (list) pricepoint's keywords (list of Keyword objects)
220
+ def keywords
221
+ return nil if json.keywords.nil?
222
+ json.keywords.children.values.map{|c| ::Allorails::Keyword(c)}
223
+ end
224
+
225
+ ## Provides the pricepoint's description
226
+ # @return (string) pricepoint's description
227
+ node_reader :description
228
+
229
+ end
230
+
231
+
232
+ ## Class providing object mapping of a partner item
233
+ class Partner < Base
234
+
235
+ ## Provides the partner id
236
+ # @return (int) partner id
237
+ node_reader :id, Integer
238
+
239
+ ## Provides the parnter's amount share
240
+ # @return (float) parnter's amount share
241
+ node_reader :share, Float
242
+
243
+ ## Provides the associated map id
244
+ # @return (int) map id
245
+ def map
246
+ return nil unless json.map.is_a?(String) && json.map.length > 0
247
+ json.map.to_i
248
+ end
249
+
250
+ end
251
+
252
+
253
+ ## Class providing object mapping of a code item
254
+ class Code < Base
255
+
256
+ ## Provides the code value
257
+ # @return (string) code
258
+ node_reader :value
259
+
260
+ ## Provides the pricepoint's description
261
+ # @return (string) pricepoint's description
262
+ node_reader :pricepoint, ::Allorails::Pricepoint
263
+
264
+ ## Provides price information
265
+ # @return (Price) price information
266
+ node_reader :price, ::Allorails::Price
267
+
268
+ ## Provides paid price information
269
+ # @return (Price) paid price information
270
+ node_reader :paid, ::Allorails::Price
271
+
272
+ ## Provides the pricepoint's payout
273
+ # @return (Payout) pricepoint's payout
274
+ node_reader :payout, ::Allorails::Payout
275
+
276
+ end
277
+
278
+ end