allorails 0.3.1

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,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