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.
data/Manifest ADDED
@@ -0,0 +1,16 @@
1
+ README.md
2
+ Rakefile
3
+ allorails.gemspec
4
+ init.rb
5
+ lib/allorails.rb
6
+ lib/allorails/api/api.rb
7
+ lib/allorails/core.rb
8
+ lib/allorails/errors/errors.rb
9
+ lib/allorails/rails.rb
10
+ lib/allorails/request/request.rb
11
+ lib/allorails/response/model.rb
12
+ lib/allorails/response/response.rb
13
+ test/allorails_spec.rb
14
+ test/test-conf-sample.yml
15
+ test/test-conf.yml
16
+ Manifest
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ *IMPORTANT:* Allorails is still being developed and tested. Use at your own risk ;)
2
+
3
+ ## Allorails
4
+
5
+ Allorails is a Ruby gem which allows to interact with Allopass's online payment REST API.
6
+
7
+ It is a Ruby port of the Allopass ApiKit for Python written by Pierre Geoffroy and available [here](http://developer.allopass.com/apidoc/kit/python3.1/index.html).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('allorails', '0.3.1') do |p|
6
+ p.description = "Ruby client for the Allopass online payment REST API"
7
+ p.url = "http://github.com/davb/allorails"
8
+ p.author = "Davide Bonapersona"
9
+ p.email = "davide@feeligo.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/allorails.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "allorails"
5
+ s.version = "0.3.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Davide Bonapersona"]
9
+ s.date = "2012-05-08"
10
+ s.description = "Ruby client for the Allopass online payment REST API"
11
+ s.email = "davide@feeligo.com"
12
+ s.extra_rdoc_files = ["README.md", "lib/allorails.rb", "lib/allorails/api/api.rb", "lib/allorails/core.rb", "lib/allorails/errors/errors.rb", "lib/allorails/rails.rb", "lib/allorails/request/request.rb", "lib/allorails/response/model.rb", "lib/allorails/response/response.rb"]
13
+ s.files = ["README.md", "Rakefile", "allorails.gemspec", "init.rb", "lib/allorails.rb", "lib/allorails/api/api.rb", "lib/allorails/core.rb", "lib/allorails/errors/errors.rb", "lib/allorails/rails.rb", "lib/allorails/request/request.rb", "lib/allorails/response/model.rb", "lib/allorails/response/response.rb", "test/allorails_spec.rb", "test/test-conf-sample.yml", "test/test-conf.yml", "Manifest"]
14
+ s.homepage = "http://github.com/davb/allorails"
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Allorails", "--main", "README.md"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "allorails"
18
+ s.rubygems_version = "1.8.21"
19
+ s.summary = "Ruby client for the Allopass online payment REST API"
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ else
26
+ end
27
+ else
28
+ end
29
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'allorails'
@@ -0,0 +1,203 @@
1
+ module Allorails
2
+
3
+ class Api
4
+
5
+ attr_accessor :email
6
+
7
+ ## Constructor
8
+ #
9
+ # @param configuration_email_account (string) Email of the configurated account
10
+ # If email is null, the first account is considered
11
+ def initialize(email = nil)
12
+ self.email = email
13
+ end
14
+
15
+ ## Method performing a onetime pricing request
16
+ #
17
+ # @param parameters (Hash) Query string parameters of the API call
18
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
19
+ #
20
+ # @return (ApiResponse) The API call response
21
+ # Will be a OnetimePricingResponse instance if mapping is true, an ApiResponse if not
22
+ #
23
+ # @code
24
+ # # Make sure the apikit is in your search path
25
+ # import allopass_apikit.api
26
+ # api = allopass_apikit.api.AllopassAPI()
27
+ # response = api.getOnetimePricing({'site_id': 127042, 'country': 'FR'})
28
+ # print("{}\n-----".format(response.getWebsite().getName()))
29
+ # for country in response.getCountries()
30
+ # print("{}\n-----".format(country.getCode()))
31
+ # print("{}\n-----".format(country.getName()))
32
+ # @endcode
33
+ def get_onetime_pricing(parameters, mapping = true)
34
+ Allorails::Request::OnetimePricingRequest.new(parameters, mapping, self.email).call
35
+ end
36
+
37
+ ## Method performing a onetime discrete pricing request
38
+ #
39
+ # @param parameters (array) Query string parameters of the API call
40
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
41
+ #
42
+ # @return (ApiResponse) The API call response
43
+ # Will be a OnetimePricingResponse instance if mapping is true, an ApiResponse if not
44
+ #
45
+ # @code
46
+ # # Make sure the apikit is in your search path
47
+ # import allopass_apikit.api
48
+ # api = allopass_apikit.api.AllopassAPI()
49
+ # response = api.getOnetimeDiscretePricing({'site_id': 127042, 'country': 'FR', 'amount': 12})
50
+ # print("{}\n-----".format(response.getWebsite().getName()))
51
+ # for country in response.getCountries()
52
+ # print("{}\n-----".format(country.getCode()))
53
+ # print("{}\n-----".format(country.getName()))
54
+ # @endcode
55
+ def get_onetime_discrete_pricing(parameters, mapping = true)
56
+ Allorails::Request::OnetimeDiscretePricingRequest.new(parameters, mapping, self.email).call
57
+ end
58
+
59
+ ## Method performing a onetime validate codes request
60
+ #
61
+ # @param parameters (array) Query string parameters of the API call
62
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
63
+ #
64
+ # @return (ApiResponse) The API call response
65
+ # Will be a OnetimeValidateCodesResponse instance if mapping is true, an ApiResponse if not
66
+ #
67
+ # @code
68
+ # # Make sure the apikit is in your search path
69
+ # import allopass_apikit.api
70
+ # api = allopass_apikit.api.AllopassAPI()
71
+ # response = api.validateCodes({'site_id': 127042, 'product_id': 354926, 'code': ('9M7QU457',)})
72
+ # print("{}\n-----".format(response->getStatus()))
73
+ # print("{}\n-----".format(response->getStatusDescription()))
74
+ # @endcode
75
+ def validate_codes(parameters, mapping = true)
76
+ Allorails::Request::OnetimeValidateCodesRequest.new(parameters, mapping, self.email).call
77
+ end
78
+
79
+ ## Method performing a onetime button request
80
+ #
81
+ # @param parameters (array) Query string parameters of the API call
82
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
83
+ #
84
+ # @return (ApiResponse) The API call response
85
+ # Will be a OnetimeButtonResponse instance if mapping is true, an ApiResponse if not
86
+ #
87
+ # @code
88
+ # # Make sure the apikit is in your search path
89
+ # import allopass_apikit.api
90
+ # api = allopass_apikit.api.AllopassAPI()
91
+ # response = api.createButton({'site_id': 127042, 'amount': 12.3, 'reference_currency': 'EUR', 'price_mode': 'price', 'price_policy': 'high-only', 'product_name': 'premium sms access', 'forward_url': 'http://product-page.com'})
92
+ # print("{}\n-----".format(response.getButtonId()))
93
+ # print("{}\n-----".format(response.getBuyUrl()))
94
+ # @endcode
95
+ def create_button(parameters = {}, mapping = true)
96
+ Allorails::Request::OnetimeButtonRequest.new(parameters, mapping, self.email).call
97
+ end
98
+
99
+ ## Method performing a onetime discrete button request
100
+ #
101
+ # @param parameters (array) Query string parameters of the API call
102
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
103
+ #
104
+ # @return (ApiResponse) The API call response
105
+ # Will be a OnetimeButtonResponse instance if mapping is true, an ApiResponse if not
106
+ #
107
+ # @code
108
+ # # Make sure the apikit is in your search path
109
+ # import allopass_apikit.api
110
+ # api = allopass_apikit.api.AllopassAPI()
111
+ # response = api.createDiscreteButton({'site_id': 127042, 'amount': 1.1, 'reference_currency': 'EUR', 'price_mode': 'price', 'price_policy': 'high-only', 'product_name': 'premium sms access', 'forward_url': 'http://product-page.com'})
112
+ # print("{}\n-----".format(response.getButtonId()))
113
+ # print("{}\n-----".format(response.getBuyUrl()))
114
+ # @endcode
115
+ def create_discrete_button(parameters = {}, mapping = true)
116
+ Allorails::Request::OnetimeDiscreteButtonRequest.new(parameters, mapping, self.email).call
117
+ end
118
+
119
+ ## Method performing a product detail request
120
+ #
121
+ # @param id (integer) The product id
122
+ # @param parameters (array) Query string parameters of the API call
123
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
124
+ #
125
+ # @return (ApiResponse) The API call response
126
+ # Will be a ProductDetailResponse instance if mapping is true, an ApiResponse if not
127
+ #
128
+ # @code
129
+ # # Make sure the apikit is in your search path
130
+ # import allopass_apikit.api
131
+ # api = allopass_apikit.api.AllopassAPI()
132
+ # response = api.getProduct(354926)
133
+ # print({}"\n-----".format(response.getName()))
134
+ # @endcode
135
+ def get_product(id, parameters = {}, mapping = true)
136
+ Allorails::Request::ProductDetailRequest.new(parameters.merge({'id'=>id}), mapping, self.email).call
137
+ end
138
+
139
+ ## Method performing a transaction prepare request
140
+ #
141
+ # @param parameters (array) Query string parameters of the API call
142
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
143
+ #
144
+ # @return (ApiResponse) The API call response
145
+ # Will be a TransactionPrepareResponse instance if mapping is true, an ApiResponse if not
146
+ #
147
+ # @code
148
+ # # Make sure the apikit is in your search path
149
+ # import allopass_apikit.api
150
+ # api = allopass_apikit.api.AllopassAPI()
151
+ # response = api.prepareTransaction({'site_id': 127042, 'pricepoint_id': 2, 'product_name': 'premium calling product', 'forward_url': 'http://product-page.com', 'amount': 15})
152
+ # print("{}\n-----".format(response.getBuyUrl()))
153
+ # print("{}\n-----".format(response.getCheckoutButton()))
154
+ # @endcode
155
+ def prepareTransaction(parameters, mapping = true)
156
+ Allorails::Request::TransactionPrepareRequest.new(parameters, mapping, self.email).call
157
+ end
158
+
159
+ ## Method performing a transaction detail request based on the transaction id
160
+ #
161
+ # @param id (string) The transaction id
162
+ # @param parameters (array) Query string parameters of the API call
163
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
164
+ #
165
+ # @return (ApiResponse) The API call response
166
+ # Will be a TransactionDetailResponse instance if mapping is true, an ApiResponse if not
167
+ #
168
+ # @code
169
+ # # Make sure the apikit is in your search path
170
+ # import allopass_apikit.api
171
+ # api = allopass_apikit.api.AllopassAPI()
172
+ # response = api.getTransaction('3f5506ac-5345-45e4-babb-96570aafdf6a');
173
+ # print("{}\n-----".format(response.getPaid().getCurrency()))
174
+ # print("{}\n-----".format(response.getPaid().getAmount()))
175
+ # @endcode
176
+ def getTransaction(id, parameters = {}, mapping = true)
177
+ Allorails::Request::TransactionDetailRequest.new(parameters.merge({'id'=>id}), mapping, self.email).call
178
+ end
179
+
180
+ ## Method performing a transaction detail request based on the merchant transaction id
181
+ #
182
+ # @param id (string) The merchant transaction id
183
+ # @param parameters (array) Query string parameters of the API call
184
+ # @param mapping (boolean) Should the response be an object mapping or a plain response
185
+ #
186
+ # @return (ApiResponse) The API call response
187
+ # Will be a TransactionDetailResponse instance if mapping is true, an ApiResponse if not
188
+ #
189
+ # @code
190
+ # # Make sure the apikit is in your search path
191
+ # import allopass_apikit.api
192
+ # api = allopass_apikit.api.AllopassAPI()
193
+ # response = api.getTransactionMerchant('TRX20091112134569B8');
194
+ # print("{}\n-----".format(response.getPaid().getCurrency()))
195
+ # print("{}\n-----".format(response.getPaid().getAmount()))
196
+ # @endcode
197
+ def getTransactionMerchant(id, parameters = {}, mapping = true)
198
+ Allorails::Request::TransactionMerchantRequest.new(parameters.merge({'id'=>id}), mapping, self.email).call
199
+ end
200
+
201
+ end
202
+
203
+ end
@@ -0,0 +1,147 @@
1
+ require 'set'
2
+
3
+ module Allorails
4
+
5
+ module Core
6
+
7
+ # Holds the configuration options for Allorails
8
+ #
9
+ class Configuration
10
+
11
+ # creates a new Configuration object
12
+ # @param options
13
+ # @option options
14
+ def initialize options = {}
15
+ options.each_pair do |opt_name, value|
16
+ opt_name = opt_name.to_sym
17
+ if self.class.accepted_options.include?(opt_name)
18
+ supplied[opt_name] = value
19
+ end
20
+ end
21
+ end
22
+
23
+ # creates a new Configuration object with the given modifications
24
+ # does not modify the current object
25
+ def with options = {}
26
+ # symbolize option keys
27
+ options = symbolize_keys options
28
+ values = supplied.merge(options)
29
+
30
+ if supplied == values
31
+ self # no changes
32
+ else
33
+ self.class.new(values)
34
+ end
35
+ end
36
+
37
+ # API key and secret key depend on the account
38
+ def api_key email = nil
39
+ account(email)[:api_key]
40
+ end
41
+
42
+ def private_key email = nil
43
+ account(email)[:private_key]
44
+ end
45
+
46
+
47
+ protected
48
+
49
+ # symbolize Hash keys
50
+ def symbolize_keys hash
51
+ hash.inject({}) {|h, (k,v)| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v; h }
52
+ end
53
+
54
+
55
+ # Returns the account matching a given email
56
+ #
57
+ # @param email (string) The email identifying the account
58
+ # If email is null, the first account is considered
59
+ #
60
+ # @return (xml.etree.ElementTree.ElementTree) Object representation of the account
61
+ #
62
+ # @throws ApiConfAccountNotFoundError If an email is provided but can't be found
63
+ #
64
+ def account(email = nil)
65
+ if accounts.length == 0
66
+ raise Allorails::ApiConfAccountNotFoundError, "No account found in config. You must configure at least one account."
67
+ else
68
+ # if email is null, the first account is considered
69
+ return accounts[accounts.keys.first] if email.nil?
70
+ # find the account corresponding to the email
71
+ return accounts[email] if accounts.has_key?(email)
72
+ end
73
+ # raise ApiConfAccountNotFoundError if email is provided but can't be found
74
+ raise Allorails::ApiConfAccountNotFoundError, "Missing configuration for account `#{email}`"
75
+ end
76
+
77
+ # supplied options
78
+ def supplied
79
+ @supplied ||= {}
80
+ end
81
+
82
+ # class methods
83
+ class << self
84
+
85
+ # accepted options
86
+ def accepted_options
87
+ @options ||= Set.new
88
+ end
89
+
90
+ # used internally to register a configuration option
91
+ def add_option name, default_value = nil
92
+ # marks the option as accepted
93
+ accepted_options << name
94
+ # defines an accessor method for the option
95
+ define_method(name) do
96
+ if supplied.has_key?(name)
97
+ supplied[name]
98
+ else
99
+ default_value
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+
106
+ end #-- end class << self
107
+
108
+ # registers configuration options
109
+ add_option :accounts, {}
110
+ add_option :default_hash, 'sha1'
111
+ add_option :default_format, 'json'
112
+ add_option :network_timeout, 20
113
+ add_option :network_protocol, 'http'
114
+ add_option :network_port, 80
115
+ add_option :host, 'api.allopass.com'
116
+
117
+ end #-- end class Configuration
118
+
119
+ end #-- end module Core
120
+
121
+ class << self
122
+
123
+ @@config = nil
124
+
125
+ # The global configuration for Allorails
126
+ # generally you would set your configuration options once, after
127
+ # loading the allorails gem.
128
+ #
129
+ # Allorails.config({
130
+ # :accounts => {
131
+ # :your@email.com => {
132
+ # :api_key => 'API_KEY',
133
+ # :private_key => 'PRIVATE_KEY'
134
+ # }
135
+ # },
136
+ # :network_port => PORT
137
+ # })
138
+ #
139
+ def config options = {}
140
+ @@config ||= Core::Configuration.new
141
+ @@config = @@config.with(options) unless options.empty?
142
+ @@config
143
+ end
144
+
145
+ end
146
+
147
+ end
@@ -0,0 +1,28 @@
1
+ module Allorails
2
+
3
+
4
+ class AllopassApikitError < StandardError
5
+ end
6
+
7
+ class ApiConfAccountNotFoundError < StandardError
8
+ end
9
+ class ApiConfFileCorruptedError < StandardError
10
+ end
11
+ class ApiConfFileMissingError < StandardError
12
+ end
13
+ class ApiConfFileMissingSectionError < StandardError
14
+ end
15
+ class ApiFalseResponseSignatureError < StandardError
16
+ end
17
+
18
+ class ApiMissingHashFeatureError < StandardError
19
+ end
20
+ class ApiRemoteErrorError < StandardError
21
+ end
22
+
23
+ class ApiUnavailableResourceError < StandardError
24
+ end
25
+ class ApiWrongFormatResponseError < StandardError
26
+ end
27
+
28
+ end
@@ -0,0 +1,75 @@
1
+ require 'yaml'
2
+
3
+ module Allorails
4
+
5
+ if Object.const_defined?(:Rails) and Rails.const_defined?(:Railtie)
6
+
7
+ class Railtie < Rails::Railtie
8
+
9
+ initializer "allorails.initialize" do |app|
10
+ Allorails::Rails.setup
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+
18
+ module Rails
19
+
20
+ def self.setup
21
+ load_yaml_config
22
+ #log_to_rails_logger
23
+ nil
24
+ end
25
+
26
+ # Loads Allorails configuration from +RAILS_ROOT/config/allorails.yml+
27
+ #
28
+ # TODO: this configuration file is optional, you can instead use Ruby
29
+ # to configure Allorails inside an initializer
30
+ # (e.g. +RAILS_ROOT/config/initializers/allorails.rb)
31
+ #
32
+ # If you use the yaml configuration file, it should include one section for
33
+ # each Rails environment:
34
+ #
35
+ # development:
36
+ # api_key: YOUR_API_KEY
37
+ # secret_key: YOUR_SECRET_KEY
38
+ #
39
+ # production:
40
+ # api_key: YOUR_API_KEY
41
+ # secret_key: YOUR_SECRET_KEY
42
+ #
43
+ # ERB tags are allowed inside the yaml file: you can do things like
44
+ # api_key: <%= read_from_somewhere_else %>
45
+ #
46
+ def self.load_yaml_config
47
+ path = Pathname.new("#{rails_root}/config/allorails.yml")
48
+ if File.exists?(path)
49
+ cfg = YAML::load(ERB.new(File.read(path)).result)
50
+ unless cfg[rails_env]
51
+ raise "config/allorails.yml is missing a section for `#{rails_env}`"
52
+ end
53
+ Allorails.config(cfg[rails_env])
54
+ end
55
+ end
56
+
57
+ protected
58
+
59
+ def self.rails_env
60
+ ::Rails.respond_to?(:env) ? ::Rails.env : RAILS_ENV
61
+ end
62
+
63
+ # @private
64
+ def self.rails_root
65
+ ::Rails.respond_to?(:root) ? ::Rails.root.to_s : RAILS_ROOT
66
+ end
67
+
68
+ # @private
69
+ def self.rails_logger
70
+ ::Rails.respond_to?(:logger) ? ::Rails.logger : ::RAILS_DEFAULT_LOGGER
71
+ end
72
+
73
+ end
74
+
75
+ end