distribution-api-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d85469e19b8fcfc2d55a940977022e2a04de424
4
+ data.tar.gz: 9ba0b2f6074e332ecdc6a928bf5e153db73fb989
5
+ SHA512:
6
+ metadata.gz: 5b5093ef7c06e7d7b176f851735c5b1b8d119153840f4f58ac031856441022ae42a55da5fc7812c83b5b0353ded9df5ca60f429df07cd7cfd8fa2ac55064f4a4
7
+ data.tar.gz: 423d396379dab2fc008f4639476e6ff8c14c645e93f71e3b87eaab78ea154c18bd1ac998d81226b88f89109268bb33a67b07c04638745afb9157b25f4789fe47
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015 Wizypay - Chaker Nakhli
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,53 @@
1
+ require 'time'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'securerandom'
5
+ require 'rest-client'
6
+ require 'simple-hmac'
7
+ require 'json'
8
+
9
+ module DistributionApi
10
+ class << self
11
+ attr_accessor :api_endpoint, :api_key, :api_secret
12
+ end
13
+
14
+ def self.setup(api_key, api_secret, api_endpoint='https://distribution.api.wizypay.com/v1')
15
+ self.api_endpoint = api_endpoint
16
+ self.api_key = api_key
17
+ self.api_secret = api_secret
18
+ end
19
+
20
+ def self.create_card(reference, amount, currency, merchant_id, user)
21
+ user = user.to_json if user.is_a?(Hash)
22
+ payload = { amount: amount, currency: currency, merchant_id: merchant_id, reference: reference, user: user }
23
+ req_params = { url: "#{api_endpoint}/cards", method: :post, headers: { accept: :json }, payload: payload }
24
+ req = RestClient::Request.new(req_params)
25
+ req.sign!(api_key, api_secret)
26
+ parse_response req.execute
27
+ end
28
+
29
+ def self.cancel_card(reference)
30
+ req_params = { url: ("#{api_endpoint}/cards/#{URI::encode_www_form_component reference}/cancel"), method: :post, headers: { accept: :json }, payload: {} }
31
+ req = RestClient::Request.new(req_params)
32
+ req.sign!(api_key, api_secret)
33
+ req.execute
34
+ end
35
+
36
+ def self.card_url(reference)
37
+ timestamp = Time.now.utc.httpdate
38
+ security = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', api_secret, "#{reference}\n#{timestamp}"))
39
+ query_string = {
40
+ key: api_key,
41
+ timestamp: timestamp,
42
+ reference: reference,
43
+ security: security
44
+ }.map { |k, v| "#{k}=#{URI::encode_www_form_component(v)}" }.join('&')
45
+ "#{api_endpoint}/widget?#{query_string}"
46
+ end
47
+
48
+ private
49
+
50
+ def self.parse_response(response)
51
+ Hash[JSON::parse(response).map { |k,v| [k.to_sym, v] }]
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module DistributionApi
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'DistributionApi::cancel_card' do
4
+
5
+ let(:api_key) { 'key' }
6
+ let(:api_secret) { 'secret' }
7
+ let(:api_endpoint) { 'https://distribution.api.wizypay.com/v1' }
8
+ let(:reference) { '85fb584c-72cb-4f35-b307-ac5442ef7153' }
9
+ let(:cancel_request) { stub_request(:post, "#{api_endpoint}/cards/#{reference}/cancel").
10
+ with(headers: { 'Accept' => 'application/json',
11
+ 'Authorization' => /WIZYPAY #{api_key}:.*/,
12
+ 'Content-Type' => 'application/x-www-form-urlencoded' }) }
13
+ before do
14
+ DistributionApi::setup(api_key, api_secret, api_endpoint)
15
+ end
16
+
17
+ context 'success' do
18
+ it 'returns empty body' do
19
+ request = cancel_request.to_return(status: 200, body: '')
20
+ response = DistributionApi::cancel_card(reference)
21
+ expect(request).to have_been_made
22
+ expect(response).to be_empty
23
+ end
24
+ end
25
+
26
+ context 'failure' do
27
+ context '4XX' do
28
+ it "throws #{RestClient::Exception}" do
29
+ request = cancel_request.to_return(status: 401, body: { errors: { base: ['authentication_failed'] } }.to_json)
30
+ expect do
31
+ DistributionApi::cancel_card(reference)
32
+ end.to raise_error(RestClient::Exception)
33
+ expect(request).to have_been_made
34
+ end
35
+ end
36
+
37
+ context 'timeout' do
38
+ it "throws #{RestClient::Exception}" do
39
+ request = cancel_request.to_timeout
40
+ expect do
41
+ DistributionApi::cancel_card(reference)
42
+ end.to raise_error(RestClient::Exception)
43
+ expect(request).to have_been_made
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'time'
3
+ require 'URI'
4
+
5
+ RSpec.describe 'DistributionApi::create_card' do
6
+
7
+ let(:api_key) { 'key' }
8
+ let(:api_secret) { 'secret' }
9
+ let(:api_endpoint) { 'https://distribution.api.wizypay.com/v1' }
10
+ let(:reference) { '85fb584c-72cb-4f35-b307-ac5442ef7153' }
11
+
12
+ before do
13
+ DistributionApi::setup(api_key, api_secret, api_endpoint)
14
+ end
15
+
16
+ it 'returns ' do
17
+ t = Time.new('2015-10-30T21:00:00+001')
18
+ Timecop.freeze(t) do
19
+ url = DistributionApi::card_url(reference)
20
+ expect(url).to eq("#{api_endpoint}/widget?key=#{URI::encode_www_form_component api_key}"+
21
+ "&timestamp=#{URI::encode_www_form_component t.httpdate}" +
22
+ "&reference=#{URI::encode_www_form_component reference}"+
23
+ "&security=0fKNCz6hux0IjNCz31JHgzh35gqLTAIM8z3iNhSkC7g%3D")
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'DistributionApi::create_card' do
4
+
5
+ let(:api_key) { 'key' }
6
+ let(:api_secret) { 'secret' }
7
+ let(:api_endpoint) { 'https://distribution.api.wizypay.com/v1' }
8
+ let(:user) { { id: 33, first_name: 'Nicolas', last_name: 'Cage' } }
9
+ let(:reference) { '85fb584c-72cb-4f35-b307-ac5442ef7153' }
10
+ let(:merchant_id) { '91' }
11
+ let(:amount) { '5000' }
12
+ let(:currency) { 'EUR' }
13
+ let(:create_request) { stub_request(:post, "#{api_endpoint}/cards").
14
+ with(body: { amount: amount, currency: currency, merchant_id: merchant_id,
15
+ reference: reference, user: user.to_json },
16
+ headers: { 'Accept' => 'application/json',
17
+ 'Authorization' => /WIZYPAY #{api_key}:.*/,
18
+ 'Content-Type' => 'application/x-www-form-urlencoded' }) }
19
+ before do
20
+ DistributionApi::setup(api_key, api_secret, api_endpoint)
21
+ end
22
+
23
+ context 'success' do
24
+ it 'returns response as hash' do
25
+ response_body = {
26
+ reference: reference,
27
+ type: 'Mastercard',
28
+ amount: amount,
29
+ currency: currency,
30
+ merchant_id: merchant_id,
31
+ user_id: user[:id]
32
+ }
33
+ request = create_request.to_return(status: 200, body: response_body.to_json)
34
+ response = DistributionApi::create_card(reference, amount, currency, merchant_id, user)
35
+ expect(request).to have_been_made
36
+ expect(response).to match(response_body)
37
+ end
38
+ end
39
+
40
+ context 'failure' do
41
+ context '4XX' do
42
+ it "throws #{RestClient::Exception}" do
43
+ request = create_request.to_return(status: 401, body: { errors: { base: ['authentication_failed'] } }.to_json)
44
+ expect do
45
+ DistributionApi::create_card(reference, amount, currency, merchant_id, user)
46
+ end.to raise_error(RestClient::Exception)
47
+ expect(request).to have_been_made
48
+ end
49
+ end
50
+
51
+ context 'timeout' do
52
+ it "throws #{RestClient::Exception}" do
53
+ request = create_request.to_timeout
54
+ expect do
55
+ DistributionApi::create_card(reference, amount, currency, merchant_id, user)
56
+ end.to raise_error(RestClient::Exception)
57
+ expect(request).to have_been_made
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,92 @@
1
+ require 'distribution-api-client'
2
+ require 'webmock/rspec'
3
+ require 'timecop'
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
7
+ # file to always be loaded, without a need to explicitly require it in any files.
8
+ #
9
+ # Given that it is always loaded, you are encouraged to keep this file as
10
+ # light-weight as possible. Requiring heavyweight dependencies from this file
11
+ # will add to the boot time of your test suite on EVERY test run, even for an
12
+ # individual file that may not need all of that loaded. Instead, consider making
13
+ # a separate helper file that requires the additional dependencies and performs
14
+ # the additional setup, and require it from the spec files that actually need it.
15
+ #
16
+ # The `.rspec` file also contains a few flags that are not defaults but that
17
+ # users commonly want.
18
+ #
19
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ end
34
+
35
+ # rspec-mocks config goes here. You can use an alternate test double
36
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
37
+ config.mock_with :rspec do |mocks|
38
+ # Prevents you from mocking or stubbing a method that does not exist on
39
+ # a real object. This is generally recommended, and will default to
40
+ # `true` in RSpec 4.
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+
44
+ # The settings below are suggested to provide a good initial experience
45
+ # with RSpec, but feel free to customize to your heart's content.
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
54
+ # For more details, see:
55
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
56
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
57
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
58
+ config.disable_monkey_patching!
59
+
60
+ # This setting enables warnings. It's recommended, but in some cases may
61
+ # be too noisy due to issues in dependencies.
62
+ config.warnings = true
63
+
64
+ # Many RSpec users commonly either run the entire suite or an individual
65
+ # file, and it's useful to allow more verbose output when running an
66
+ # individual spec file.
67
+ if config.files_to_run.one?
68
+ # Use the documentation formatter for detailed output,
69
+ # unless a formatter has already been configured
70
+ # (e.g. via a command-line flag).
71
+ config.default_formatter = 'doc'
72
+ end
73
+
74
+ # Print the 10 slowest examples and example groups at the
75
+ # end of the spec run, to help surface which specs are running
76
+ # particularly slow.
77
+ config.profile_examples = 10
78
+
79
+ # Run specs in random order to surface order dependencies. If you find an
80
+ # order dependency and want to debug it, you can fix the order by providing
81
+ # the seed, which is printed after each run.
82
+ # --seed 1234
83
+ config.order = :random
84
+
85
+ # Seed global randomization in this process using the `--seed` CLI option.
86
+ # Setting this allows you to use `--seed` to deterministically reproduce
87
+ # test failures related to randomization by passing the same `--seed` value
88
+ # as the one that triggered the failure.
89
+ Kernel.srand config.seed
90
+ end
91
+
92
+ Timecop.safe_mode = true
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: distribution-api-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chaker Nakhli
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simple-hmac
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.22'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.22'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.8'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.8'
111
+ description:
112
+ email:
113
+ - chaker@wizypay.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - LICENSE.txt
119
+ - Rakefile
120
+ - lib/distribution-api-client.rb
121
+ - lib/distribution-api/version.rb
122
+ - spec/cancel_card_spec.rb
123
+ - spec/card_url_spec.rb
124
+ - spec/create_card_spec.rb
125
+ - spec/spec_helper.rb
126
+ homepage: http://developers.wizypay.com
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options:
132
+ - "--charset=UTF-8"
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: 2.2.0
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.4.5.1
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Programmatic API to access Wizypay's Distribution API.
151
+ test_files:
152
+ - spec/cancel_card_spec.rb
153
+ - spec/card_url_spec.rb
154
+ - spec/create_card_spec.rb
155
+ - spec/spec_helper.rb