synapse_pay_rest 2.2.3 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e6838fb99b9172f2110365b17cbe0958bd35d83f
4
- data.tar.gz: c1af1430a94a956fbe9391e37d32a8a6adf81e7f
3
+ metadata.gz: 3d201dae4eb740319963ab42443361cd8fad2d5a
4
+ data.tar.gz: 40d4b70997bebff7e71f30fbc25ddc076c728cc6
5
5
  SHA512:
6
- metadata.gz: 08b62065ca6fc61717a65ac965e1278069bd23065f86feb5a5a4138b88474a63301c12ca54caaf7c984235f31446f602f0918a3f1b732091f61133a0f5a39eee
7
- data.tar.gz: 132d1b8370e090f87c7041f52744f4164801656fb105131962ca8c9705bd14ef1c238419f48f6ddc61c4b55509587e9ad60e6d11ba775b1473a2c9ab5fb7d140
6
+ metadata.gz: accdfae93f38d4d0ca80d50e63afc6a7d30f511f34569c709facd33e954baf6dea7378628dfcca88661d3b1955aefda1cf7fe73e8f49dad754b058cedd8f580b
7
+ data.tar.gz: a283391d0a7d766425d1ad52c670d5630fa535ad1d03b0eb36198b8ccc20f11d2162f05403c6e8af8d9b58c96c785d8aa1658d24eecc3b091642d9260132b833
data/.env.sample ADDED
@@ -0,0 +1,8 @@
1
+ # For development in a console
2
+ CLIENT_ID=your_sandbox_client_id
3
+ CLIENT_SECRET=your_sandbox_client_secret
4
+ FINGERPRINT=your_sandbox_fingerprint
5
+
6
+ # For running tests
7
+ TEST_CLIENT_ID=your_sandbox_client_id
8
+ TEST_CLIENT_SECRET=your_sandbox_client_secret
data/.gitignore CHANGED
@@ -30,7 +30,7 @@ build/
30
30
 
31
31
  # for a library or gem, you might want to ignore these files since the code is
32
32
  # intended to run in multiple environments; otherwise, check them in:
33
- # Gemfile.lock
33
+ Gemfile.lock
34
34
  # .ruby-version
35
35
  # .ruby-gemset
36
36
 
@@ -42,4 +42,4 @@ build/
42
42
  ## ENV variables and other secrets
43
43
  .env
44
44
  test.txt
45
- *.yml
45
+ *.yml
data/README.md CHANGED
@@ -2,19 +2,8 @@
2
2
 
3
3
  Native API library for SynapsePay REST v3.x
4
4
 
5
- Originally developed as a simple wrapper to handle the headers and endpoint URLs for each API request, as of v2.0.0 it now handles creation of User, Node, Transaction and related objects to remove the necessity of dealing with raw payload and response JSON.
6
-
7
5
  Not all API endpoints are supported.
8
6
 
9
- **Pre-2.0.0 users**
10
-
11
- There are significant changes but backwards compatibility has been mostly maintained by building on top of the base API wrapper. You can still use the previous classes but note the following changes:
12
-
13
- - `ArgumentError` will be raised for missing payloads or other required arguments, where `RuntimeError` was raised previously.
14
- - `development_mode` now defaults to true (gem previously defaulted to production).
15
- - KYC 1.0 methods for uploading documents have been deprecated. Please contact SynapsePay if you need to update to KYC 2.0.
16
- - API errors will now raise `SynapsePayRest::Error`s instead returning a JSON hash (and sometimes obfuscating the API error message).
17
-
18
7
  ## Installation
19
8
 
20
9
  Add this line to your application's Gemfile:
@@ -43,16 +32,11 @@ $ gem install synapse_pay_rest
43
32
 
44
33
  ## Contributing
45
34
 
46
- For minor issues, just open a pull request. For larger changes or features, please email steven@synapsepay.com.Please document and test any public constants/methods. Open an issue or email steven@synapsepay.com if you have any questions.
35
+ For minor issues, just open a pull request. For larger changes or features, please email steven@synapsepay.com. Please document and test any public constants/methods. Open an issue or email steven@synapsepay.com if you have any questions.
47
36
 
48
37
  ## Running the Test Suite
49
38
 
50
- Make sure these values are set as enviroment variables (using [dotenv](https://github.com/bkeepers/dotenv) for example):
51
-
52
- ```
53
- CLIENT_ID=your_sandbox_client_id
54
- CLIENT_SECRET=your_sandbox_client_secret
55
- ```
39
+ If you haven't already, run `cp .env.sample .env` and set the `TEST_CLIENT_ID` and `TEST_CLIENT_SECRET` environment variables.
56
40
 
57
41
  To run all tests, execute:
58
42
 
@@ -60,7 +44,7 @@ To run all tests, execute:
60
44
  rake
61
45
  ```
62
46
 
63
- To run a specific file or test, install the [m](https://github.com/qrush/m) gem and execute:
47
+ To run a specific file or test run:
64
48
 
65
49
  ```bash
66
50
  m path/to/file:line_number
data/bin/console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'synapse_pay_rest'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require 'pry'
11
+ # Pry.start
12
+
13
+ require 'dotenv'
14
+ Dotenv.load
15
+
16
+ require 'irb'
17
+ IRB.start
@@ -57,9 +57,9 @@ module SynapsePayRest
57
57
  # HTTP response from API
58
58
  #
59
59
  # @return [Hash] API response
60
- def create(user_id:, node_id:, payload:)
60
+ def create(user_id:, node_id:, payload:, idempotency_key: nil)
61
61
  path = create_transaction_path(user_id: user_id, node_id: node_id)
62
- client.post(path, payload)
62
+ client.post(path, payload, idempotency_key: idempotency_key)
63
63
  end
64
64
 
65
65
  # Sends a PATCH request to /trans endpoint to update a transaction.
@@ -28,7 +28,7 @@ module SynapsePayRest
28
28
  def initialize(client_id:, client_secret:, ip_address:, fingerprint: nil,
29
29
  development_mode: true, **options)
30
30
  base_url = if development_mode
31
- 'https://sandbox.synapsepay.com/api/3'
31
+ 'https://uat-api.synapsefi.com/v3.1'
32
32
  else
33
33
  'https://synapsepay.com/api/3'
34
34
  end
@@ -54,20 +54,20 @@ module SynapsePayRest
54
54
  # @todo need to add an error message for various 202 cases (fingerprint, mfa, etc)
55
55
  # @todo doesn't do well when there's an html response from nginx for bad gateway/timeout
56
56
  ERRORS = {
57
- 400 => SynapsePayRest::Error::BadRequest,
58
- 401 => SynapsePayRest::Error::Unauthorized,
59
- 402 => SynapsePayRest::Error::RequestDeclined,
60
- 403 => SynapsePayRest::Error::Forbidden,
61
- 404 => SynapsePayRest::Error::NotFound,
62
- 406 => SynapsePayRest::Error::NotAcceptable,
63
- 409 => SynapsePayRest::Error::Conflict,
64
- 415 => SynapsePayRest::Error::UnsupportedMediaType,
65
- 422 => SynapsePayRest::Error::UnprocessableEntity,
66
- 429 => SynapsePayRest::Error::TooManyRequests,
67
- 500 => SynapsePayRest::Error::InternalServerError,
68
- 502 => SynapsePayRest::Error::BadGateway,
69
- 503 => SynapsePayRest::Error::ServiceUnavailable,
70
- 504 => SynapsePayRest::Error::GatewayTimeout
57
+ '400' => SynapsePayRest::Error::BadRequest,
58
+ '401' => SynapsePayRest::Error::Unauthorized,
59
+ '402' => SynapsePayRest::Error::RequestDeclined,
60
+ '403' => SynapsePayRest::Error::Forbidden,
61
+ '404' => SynapsePayRest::Error::NotFound,
62
+ '406' => SynapsePayRest::Error::NotAcceptable,
63
+ '409' => SynapsePayRest::Error::Conflict,
64
+ '415' => SynapsePayRest::Error::UnsupportedMediaType,
65
+ '422' => SynapsePayRest::Error::UnprocessableEntity,
66
+ '429' => SynapsePayRest::Error::TooManyRequests,
67
+ '500' => SynapsePayRest::Error::InternalServerError,
68
+ '502' => SynapsePayRest::Error::BadGateway,
69
+ '503' => SynapsePayRest::Error::ServiceUnavailable,
70
+ '504' => SynapsePayRest::Error::GatewayTimeout
71
71
  }.freeze
72
72
 
73
73
  # The SynapsePay API Error Code
@@ -86,10 +86,10 @@ module SynapsePayRest
86
86
  # @param body [String]
87
87
  # @param code [Integer]
88
88
  # @return [SynapsePayRest::Error]
89
- def error_from_response(body, code)
89
+ def from_response(body)
90
90
  # require 'pry'; binding.pry
91
- klass = ERRORS[code.to_i] || SynapsePayRest::Error
92
- message, error_code = parse_error(body)
91
+ message, error_code, http_code = parse_error(body)
92
+ klass = ERRORS[http_code] || SynapsePayRest::Error
93
93
  klass.new(message: message, code: error_code, response: body)
94
94
  end
95
95
 
@@ -97,9 +97,9 @@ module SynapsePayRest
97
97
 
98
98
  def parse_error(body)
99
99
  if body.nil? || body.empty?
100
- ['', nil]
100
+ ['', nil, nil]
101
101
  elsif body.is_a?(Hash) && body['error'].is_a?(Hash)
102
- [body['error']['en'], body['error_code']]
102
+ [body['error']['en'], body['error_code'], body['http_code']]
103
103
  end
104
104
  end
105
105
  end
@@ -112,7 +112,7 @@ module SynapsePayRest
112
112
  # @return [SynapsePayRest::Error]
113
113
  def initialize(message: '', code: nil, response: {})
114
114
  super(message)
115
- @code = code
115
+ @code = code
116
116
  @response = response
117
117
  end
118
118
  end
@@ -21,7 +21,7 @@ module SynapsePayRest
21
21
  client_secret:, **options)
22
22
  log_to = options[:log_to] || 'stdout'
23
23
  RestClient.log = log_to if options[:logging]
24
- @logging = options[:logging]
24
+ @logging = options[:logging]
25
25
 
26
26
  @config = {
27
27
  client_id: client_id,
@@ -73,11 +73,17 @@ module SynapsePayRest
73
73
  #
74
74
  # @param path [String]
75
75
  # @param payload [Hash]
76
- #
76
+ # @param idempotency_key [String] (optional) avoid accidentally performing the same operation twice
77
+ #
77
78
  # @raise [SynapsePayRest::Error] subclass depends on HTTP response
78
79
  #
79
80
  # @return [Hash] API response
80
- def post(path, payload)
81
+ def post(path, payload, **options)
82
+ headers = get_headers
83
+ if options[:idempotency_key]
84
+ headers = headers.merge({'X-SP-IDEMPOTENCY-KEY' => options[:idempotency_key]})
85
+ end
86
+
81
87
  response = with_error_handling { RestClient.post(full_url(path), payload.to_json, headers) }
82
88
  p 'RESPONSE:', JSON.parse(response) if @logging
83
89
  JSON.parse(response)
@@ -133,7 +139,7 @@ module SynapsePayRest
133
139
  yield
134
140
  rescue RestClient::Exception => e
135
141
  body = JSON.parse(e.response.body)
136
- raise Error.error_from_response(body, body['error_code'])
142
+ raise Error.from_response(body)
137
143
  end
138
144
  end
139
145
  end
@@ -24,7 +24,6 @@ module SynapsePayRest
24
24
  raise ArgumentError, 'password must be a String' unless password.is_a?(String)
25
25
 
26
26
  payload = payload_for_create_via_bank_login(bank_name: bank_name, username: username, password: password)
27
- user.authenticate
28
27
  response = user.client.nodes.add(user_id: user.id, payload: payload)
29
28
  # MFA questions
30
29
  if response['mfa']
@@ -38,7 +38,6 @@ module SynapsePayRest
38
38
  raise ArgumentError, 'nickname must be a String' unless nickname.is_a?(String)
39
39
 
40
40
  payload = payload_for_create(nickname: nickname, **options)
41
- user.authenticate
42
41
  response = user.client.nodes.add(user_id: user.id, payload: payload)
43
42
  from_response(user, response['nodes'].first)
44
43
  end
@@ -64,7 +63,6 @@ module SynapsePayRest
64
63
  raise ArgumentError, "type must be nil or in #{NODE_TYPES_TO_CLASSES.keys}"
65
64
  end
66
65
 
67
- user.authenticate
68
66
  response = user.client.nodes.get(
69
67
  user_id: user.id,
70
68
  page: page,
@@ -221,7 +219,8 @@ module SynapsePayRest
221
219
  # @param fee_note [String] (optional)
222
220
  # @param fee_to_id [String] (optional) node id to which to send the fee
223
221
  # @param supp_id [String] (optional)
224
- #
222
+ # @param idempotency_key [String] (optional) avoid accidentally performing the same operation twice
223
+ #
225
224
  # @raise [SynapsePayRest::Error] if HTTP error or invalid argument format
226
225
  #
227
226
  # @return [SynapsePayRest::Transaction]
@@ -262,14 +261,19 @@ module SynapsePayRest
262
261
  #
263
262
  # @return [:success]
264
263
  def deactivate
265
- user.authenticate
266
- user.client.nodes.delete(user_id: user.id, node_id: id)
267
- :success
264
+ response = user.client.nodes.delete(user_id: user.id, node_id: id)
265
+ if response['_id']
266
+ # api v3.1.1
267
+ self.class.from_response(user, response)
268
+ else
269
+ # api v3.1
270
+ nil
271
+ end
268
272
  end
269
273
 
270
274
  # Checks if two BaseNode instances have same id (different instances of same record).
271
275
  def ==(other)
272
- other.instance_of?(self.class) && !id.nil? && id == other.id
276
+ other.instance_of?(self.class) && !id.nil? && id == other.id
273
277
  end
274
278
  end
275
279
  end
@@ -33,7 +33,6 @@ module SynapsePayRest
33
33
  raise ArgumentError, 'user must be a User object' unless user.is_a?(User)
34
34
  raise ArgumentError, 'id must be a String' unless id.is_a?(String)
35
35
 
36
- user.authenticate
37
36
  response = user.client.nodes.get(user_id: user.id, node_id: id)
38
37
  from_response(user, response)
39
38
  end
@@ -61,7 +60,6 @@ module SynapsePayRest
61
60
  raise ArgumentError, "type must be nil or in #{NODE_TYPES_TO_CLASSES.keys}"
62
61
  end
63
62
 
64
- user.authenticate
65
63
  response = user.client.nodes.get(
66
64
  user_id: user.id,
67
65
  page: page,
@@ -54,16 +54,8 @@ module SynapsePayRest
54
54
  # correct answer
55
55
  @mfa_verified = true
56
56
  AchUsNode.multiple_from_response(user, response['nodes'])
57
- elsif response['error_code'] == '10' && response['mfa']['message'] == mfa_message
58
- # wrong answer (mfa message the same), retry if allowed
59
- args = {
60
- message: 'incorrect bank login mfa answer',
61
- code: response['http_code'],
62
- response: response
63
- }
64
- raise SynapsePayRest::Error, args
65
57
  elsif response['error_code'] == '10'
66
- # new additional MFA question. need to call #answer_mfa with new answer
58
+ # wrong answer or new additional MFA question
67
59
  @mfa_access_token = response['mfa']['access_token']
68
60
  @mfa_message = response['mfa']['message']
69
61
  self
@@ -4,16 +4,14 @@ module SynapsePayRest
4
4
  class << self
5
5
  private
6
6
 
7
- def payload_for_create(nickname:, bank_name:, account_number:, routing_number:,
8
- name_on_account:, address:, **options)
7
+ def payload_for_create(nickname:, account_number:, routing_number:,
8
+ name_on_account:, **options)
9
9
  args = {
10
10
  type: 'WIRE-US',
11
11
  nickname: nickname,
12
- bank_name: bank_name,
13
12
  account_number: account_number,
14
13
  routing_number: routing_number,
15
- name_on_account: name_on_account,
16
- address: address
14
+ name_on_account: name_on_account
17
15
  }.merge(options)
18
16
  super(args)
19
17
  end
@@ -4,8 +4,7 @@ module SynapsePayRest
4
4
  # is intended to make it easier to use the API without knowing payload formats
5
5
  # or knowledge of REST.
6
6
  #
7
- # @todo use mixins to remove duplication between Node and BaseNode. May be
8
- # better to refactor this into a mixin altogether since this shouldn't be instantiated.
7
+ # @todo use mixins to remove duplication between Node and BaseNode.
9
8
  # @todo reduce duplicated logic between User/BaseNode/Transaction
10
9
  class Transaction
11
10
  # @!attribute [rw] node
@@ -28,11 +27,13 @@ module SynapsePayRest
28
27
  # @param ip [String]
29
28
  # @param note [String] (optional)
30
29
  # @param process_in [Integer] (optional) days until processed (default/minimum 1)
31
- # @param fee_amount [Float] (optional) fee amount to add to the transaction
32
- # @param fee_to_id [String] (optional) node id to which to send the fee (must be SYNAPSE-US)
33
- # @param fee_note [String] (optional)
30
+ # @param fees [Array] (optional) fee amounts to add to the transaction. Example: [{fee: 1.0, note: 'Test Fee', to: {id: 'fee_node_id'}}]
31
+ # @param fee_amount [Float] (deprecated) fee amount to add to the transaction
32
+ # @param fee_to_id [String] (deprecated) node id to which to send the fee (must be SYNAPSE-US)
33
+ # @param fee_note [String] (deprecated)
34
34
  # @param supp_id [String] (optional)
35
- #
35
+ # @param idempotency_key [String] (optional)
36
+ #
36
37
  # @raise [SynapsePayRest::Error] if HTTP error or invalid argument format
37
38
  #
38
39
  # @return [SynapsePayRest::Transaction]
@@ -46,16 +47,18 @@ module SynapsePayRest
46
47
  raise ArgumentError, 'node must be a type of BaseNode object' unless node.is_a?(BaseNode)
47
48
  raise ArgumentError, 'amount must be a Numeric (Integer or Float)' unless amount.is_a?(Numeric)
48
49
  [to_type, to_id, currency, ip].each do |arg|
49
- raise ArgumentError, "#{arg} must be a String" unless arg.is_a?(String)
50
+ if options[arg] && !options[arg].is_a?(String)
51
+ raise ArgumentError, "#{arg} must be a String"
52
+ end
50
53
  end
51
54
 
52
55
  payload = payload_for_create(node: node, to_type: to_type, to_id: to_id,
53
56
  amount: amount, currency: currency, ip: ip, **options)
54
- node.user.authenticate
55
57
  response = node.user.client.trans.create(
56
58
  user_id: node.user.id,
57
59
  node_id: node.id,
58
- payload: payload
60
+ payload: payload,
61
+ idempotency_key: options[:idempotency_key],
59
62
  )
60
63
  from_response(node, response)
61
64
  end
@@ -73,7 +76,6 @@ module SynapsePayRest
73
76
  raise ArgumentError, 'node must be a type of BaseNode object' unless node.is_a?(BaseNode)
74
77
  raise ArgumentError, 'id must be a String' unless id.is_a?(String)
75
78
 
76
- node.user.authenticate
77
79
  response = node.user.client.trans.get(
78
80
  user_id: node.user.id,
79
81
  node_id: node.id,
@@ -100,7 +102,6 @@ module SynapsePayRest
100
102
  end
101
103
  end
102
104
 
103
- node.user.authenticate
104
105
  response = node.user.client.trans.get(
105
106
  user_id: node.user.id,
106
107
  node_id: node.id,
@@ -137,11 +138,13 @@ module SynapsePayRest
137
138
  from: response['from'],
138
139
  to: response['to'],
139
140
  to_type: response['to']['type'],
140
- to_id: response['to']['id'],
141
- fee_amount: response['fees'].last['fee'],
142
- fee_note: response['fees'].last['note'],
143
- fee_to_id: response['fees'].last['to']['id'],
141
+ to_id: response['to']['id']
144
142
  }
143
+ if response['fees'].any?
144
+ args[:fee_amount] = response['fees'].first['fee']
145
+ args[:fee_note] = response['fees'].first['note']
146
+ args[:fee_to_id] = response['fees'].first['to']['id']
147
+ end
145
148
  self.new(args)
146
149
  end
147
150
 
@@ -170,6 +173,7 @@ module SynapsePayRest
170
173
  other['attachments'] = options[:attachments] if options[:attachments]
171
174
  payload['extra']['other'] = other if other.any?
172
175
  fees = []
176
+ # deprecated fee flow
173
177
  fee = {}
174
178
  fee['fee'] = options[:fee_amount] if options[:fee_amount]
175
179
  fee['note'] = options[:fee_note] if options[:fee_note]
@@ -177,6 +181,8 @@ module SynapsePayRest
177
181
  fee_to['id'] = options[:fee_to_id] if options[:fee_to_id]
178
182
  fee['to'] = fee_to if fee_to.any?
179
183
  fees << fee if fee.any?
184
+ # new fee flow
185
+ fees = options[:fees] if options[:fees]
180
186
  payload['fees'] = fees if fees.any?
181
187
  payload
182
188
  end
@@ -208,7 +214,13 @@ module SynapsePayRest
208
214
  trans_id: id,
209
215
  payload: payload
210
216
  )
211
- self.class.from_response(node, response['trans'])
217
+ if response['trans']
218
+ # api v3.1
219
+ self.class.from_response(node, response['trans'])
220
+ else
221
+ # api v3.1.1
222
+ self.class.from_response(node, response)
223
+ end
212
224
  end
213
225
 
214
226
  # Cancels this transaction if it has not already settled.
@@ -227,7 +239,7 @@ module SynapsePayRest
227
239
 
228
240
  # Checks if two Transaction instances have same id (different instances of same record).
229
241
  def ==(other)
230
- other.instance_of?(self.class) && !id.nil? && id == other.id
242
+ other.instance_of?(self.class) && !id.nil? && id == other.id
231
243
  end
232
244
  end
233
245
  end
@@ -164,7 +164,6 @@ module SynapsePayRest
164
164
  #
165
165
  # @return [SynapsePayRest::BaseDocument] new instance with updated info (id will be different if email or phone changed)
166
166
  def submit
167
- user.authenticate
168
167
  response = user.client.users.update(user_id: user.id, payload: payload_for_submit)
169
168
  @user = User.from_response(user.client, response)
170
169
 
@@ -210,7 +209,6 @@ module SynapsePayRest
210
209
  if changes.empty?
211
210
  raise ArgumentError, 'must provide some key-value pairs to update'
212
211
  end
213
- user.authenticate
214
212
  payload = payload_for_update(changes)
215
213
  response = user.client.users.update(user_id: user.id, payload: payload)
216
214
  @user = User.from_response(user.client, response)
@@ -11,19 +11,19 @@ module SynapsePayRest
11
11
  # Creates a document instance but does not submit it to the API. Use
12
12
  # BaseDocument#create/#update/#add_physical_documents or related methods
13
13
  # to submit the document to the API.
14
- #
15
- # @note This should only be called on subclasses of Document, not on
14
+ #
15
+ # @note This should only be called on subclasses of Document, not on
16
16
  # Document itself.
17
- #
17
+ #
18
18
  # @param type [String]
19
19
  # @param value [String] (optional) padded base64-encoded image ("data:#{mime_type};base64,#{base64}")
20
20
  # @param file_path [String] (optional) path to image file
21
21
  # @param url [String] (optional) image file url
22
22
  # @param byte_stream [String] (optional) byte representation of image
23
23
  # @param mime_type [String] (optional) mime type of byte_stream (e.g. 'image/png')
24
- #
24
+ #
25
25
  # @return [SynapsePayRest::Document]
26
- #
26
+ #
27
27
  # @see https://docs.synapsepay.com/docs/user-resources#section-physical-document-types physical document types
28
28
  # @see https://docs.synapsepay.com/docs/user-resources#section-social-document-types social document types
29
29
  # @see https://docs.synapsepay.com/docs/user-resources#section-virtual-document-types virtual document types
@@ -37,7 +37,7 @@ module SynapsePayRest
37
37
  elsif options[:value]
38
38
  value = options[:value]
39
39
  end
40
-
40
+
41
41
  super(type: type, value: value)
42
42
  end
43
43
 
@@ -46,7 +46,8 @@ module SynapsePayRest
46
46
  raise ArgumentError, 'url must be a String' unless url.is_a?(String)
47
47
  byte_stream = open(url).read
48
48
  begin
49
- mime_type = MIME::Types.type_for(url).first.content_type
49
+ # remove any query params to get the mime type
50
+ mime_type = MIME::Types.type_for(url.gsub(/\?.*$/, '')).first.content_type
50
51
  rescue
51
52
  mime_type = nil
52
53
  end
@@ -62,8 +63,7 @@ module SynapsePayRest
62
63
  # Converts the supplied image byte stream to padded base64
63
64
  def byte_stream_to_base64(byte_stream, mime_type)
64
65
  base64 = Base64.encode64(byte_stream)
65
- padding = "data:#{mime_type};base64,#{base64}"
66
- padding + base64
66
+ "data:#{mime_type};base64,#{base64}"
67
67
  end
68
68
  end
69
69
  end
@@ -1,6 +1,8 @@
1
1
  module SynapsePayRest
2
2
  # Represents a question that is triggered when a document is returned with
3
3
  # status MFA|PENDING.
4
+ #
5
+ # @deprecated
4
6
  class Question
5
7
  # @!attribute [r] question
6
8
  # @return [String] the text of the question
@@ -4,8 +4,7 @@ module SynapsePayRest
4
4
  # is intended to make it easier to use the API without knowing payload formats
5
5
  # or knowledge of REST.
6
6
  #
7
- # @todo use mixins to remove duplication between Node and BaseNode. May be
8
- # better to refactor this into a mixin altogether since this shouldn't be instantiated.
7
+ # @todo use mixins to remove duplication between Node and BaseNode.
9
8
  # @todo reduce duplicated logic between User/BaseNode/Transaction
10
9
  class User
11
10
  # @!attribute [rw] base_documents
@@ -89,6 +88,8 @@ module SynapsePayRest
89
88
  # @raise [SynapsePayRest::Error] if HTTP error or invalid argument format
90
89
  #
91
90
  # @return [Array<SynapsePayRest::User>]
91
+ #
92
+ # @note users created this way are not automatically OAuthed
92
93
  def all(client:, page: nil, per_page: nil, query: nil)
93
94
  raise ArgumentError, 'client must be a SynapsePayRest::Client' unless client.is_a?(Client)
94
95
  [page, per_page].each do |arg|
@@ -116,6 +117,8 @@ module SynapsePayRest
116
117
  # @raise [SynapsePayRest::Error] if HTTP error or invalid argument format
117
118
  #
118
119
  # @return [Array<SynapsePayRest::User>]
120
+ #
121
+ # @note users created this way are not automatically OAuthed
119
122
  def search(client:, query:, page: nil, per_page: nil)
120
123
  all(client: client, query: query, page: page, per_page: per_page)
121
124
  end
@@ -141,7 +144,7 @@ module SynapsePayRest
141
144
 
142
145
  # Constructs a user instance from a user response.
143
146
  # @note Do not call directly.
144
- def from_response(client, response)
147
+ def from_response(client, response, oauth: true)
145
148
  user = self.new(
146
149
  client: client,
147
150
  id: response['_id'],
@@ -160,13 +163,14 @@ module SynapsePayRest
160
163
  base_documents = BaseDocument.from_response(user, response)
161
164
  user.base_documents = base_documents
162
165
  end
163
- user
166
+ oauth ? user.authenticate : user
164
167
  end
165
168
 
166
169
  # Calls from_response on each member of a response collection.
170
+ # @note users created this way are not automatically OAuthed
167
171
  def multiple_from_response(client, response)
168
172
  return [] if response.empty?
169
- response.map { |user_data| from_response(client, user_data)}
173
+ response.map { |user_data| from_response(client.dup, user_data, oauth: false)}
170
174
  end
171
175
  end
172
176
 
@@ -177,6 +181,16 @@ module SynapsePayRest
177
181
  @base_documents ||= []
178
182
  end
179
183
 
184
+ # Updates the oauth token.
185
+ #
186
+ # @raise [SynapsePayRest::Error]
187
+ #
188
+ # @return [SynapsePayRest::User] (self)
189
+ def authenticate
190
+ client.users.refresh(user_id: id, payload: payload_for_refresh)
191
+ self
192
+ end
193
+
180
194
  # Updates the given key value pairs.
181
195
  #
182
196
  # @param login [Hash]
@@ -201,7 +215,6 @@ module SynapsePayRest
201
215
  raise ArgumentError, 'must provide a key-value pair to update. keys: login,
202
216
  read_only, phone_number, legal_name, remove_phone_number, remove_login'
203
217
  end
204
- authenticate
205
218
  response = client.users.update(user_id: id, payload: payload_for_update(options))
206
219
  # return an updated user instance
207
220
  self.class.from_response(client, response)
@@ -301,16 +314,6 @@ module SynapsePayRest
301
314
  update(remove_phone_number: phone_number)
302
315
  end
303
316
 
304
- # Updates the user's oauth token.
305
- #
306
- # @raise [SynapsePayRest::Error]
307
- #
308
- # @return [SynapsePayRest::User] (self)
309
- def authenticate
310
- client.users.refresh(user_id: id, payload: payload_for_refresh)
311
- self
312
- end
313
-
314
317
  # Step 1 of fingerprint registration. Requests a new fingerprint be
315
318
  # registered to the user.
316
319
  #
@@ -582,7 +585,7 @@ module SynapsePayRest
582
585
 
583
586
  # Checks if two User instances have same id (different instances of same record).
584
587
  def ==(other)
585
- other.instance_of?(self.class) && !id.nil? && id == other.id
588
+ other.instance_of?(self.class) && !id.nil? && id == other.id
586
589
  end
587
590
 
588
591
  private
@@ -27,10 +27,9 @@ module SynapsePayRest
27
27
  #
28
28
  # @return [SynapsePayRest::VirtualDocument] (self)
29
29
  #
30
- # @todo should raise error if any questions aren't answered yet.
30
+ # @deprecated
31
31
  def submit_kba
32
32
  user = base_document.user
33
- user.authenticate()
34
33
  response = user.client.users.update(user_id: user.id, payload: payload_for_kba)
35
34
  user = User.from_response(user.client, response)
36
35
  base_doc = user.base_documents.find { |doc| doc.id == base_document.id }
@@ -38,6 +37,8 @@ module SynapsePayRest
38
37
  end
39
38
 
40
39
  # Maps question set from response to Question objects.
40
+ #
41
+ # @deprecated
41
42
  def add_question_set(question_set_data)
42
43
  questions = question_set_data['questions'].map do |question_info|
43
44
  # re-map question/answer hash structure
@@ -58,6 +59,7 @@ module SynapsePayRest
58
59
 
59
60
  private
60
61
 
62
+ # @deprecated
61
63
  def payload_for_kba
62
64
  {
63
65
  'documents' => [{
@@ -1,4 +1,4 @@
1
1
  module SynapsePayRest
2
- # gem version:
3
- VERSION = '2.2.3'.freeze
2
+ # Gem version
3
+ VERSION = '3.0.1'.freeze
4
4
  end
data/samples.md CHANGED
@@ -1,8 +1,16 @@
1
+ # Setup
2
+
3
+ First, run `cp .env.sample .env` if you haven't already and make sure `CLIENT_ID`, `CLIENT_SECRET`, and `FINGERPRINT` are set.
4
+
5
+ Start a console that will load this gem and your settings from `.env` automatically.
6
+
7
+ ```
8
+ $ ./bin/console
9
+ ```
10
+
1
11
  ## Initialization
2
12
 
3
13
  ```ruby
4
- require 'synapse_pay_rest'
5
-
6
14
  args = {
7
15
  # synapse client_id
8
16
  client_id: ENV.fetch('CLIENT_ID'),
@@ -272,7 +280,7 @@ base_doc = virtual_doc.base_document
272
280
 
273
281
  ## Node Methods
274
282
 
275
- #### All Nodes for a User
283
+ #### All Nodes for a User
276
284
 
277
285
  ##### a) User#nodes
278
286
 
@@ -310,7 +318,7 @@ Returns a collection of `AchUsNode`s associated with the account unless bank req
310
318
 
311
319
  ```ruby
312
320
  login_info = {
313
- bank_name: 'bofa',
321
+ bank_name: 'fake',
314
322
  username: 'synapse_good',
315
323
  password: 'test1234'
316
324
  }
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  s.require_paths = ['lib']
19
19
 
20
+ s.required_ruby_version = '>= 2.1.0'
21
+
20
22
  s.add_dependency 'rest-client', '~> 2.0'
21
23
 
22
24
  s.add_development_dependency 'bundler', '~> 1.10'
@@ -26,4 +28,5 @@ Gem::Specification.new do |s|
26
28
  s.add_development_dependency 'dotenv', '~> 2.1.1'
27
29
  s.add_development_dependency 'faker', '~> 1.6.6'
28
30
  s.add_development_dependency 'simplecov', '~> 0.12.0'
31
+ s.add_development_dependency 'm', '~> 1.5.0'
29
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synapse_pay_rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Broderick
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-12-21 00:00:00.000000000 Z
12
+ date: 2017-02-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -123,18 +123,33 @@ dependencies:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
125
  version: 0.12.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: m
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: 1.5.0
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: 1.5.0
126
140
  description:
127
141
  email: help@synapsepay.com
128
142
  executables: []
129
143
  extensions: []
130
144
  extra_rdoc_files: []
131
145
  files:
146
+ - ".env.sample"
132
147
  - ".gitignore"
133
148
  - Gemfile
134
- - Gemfile.lock
135
149
  - LICENSE
136
150
  - README.md
137
151
  - Rakefile
152
+ - bin/console
138
153
  - lib/synapse_pay_rest.rb
139
154
  - lib/synapse_pay_rest/api/nodes.rb
140
155
  - lib/synapse_pay_rest/api/transactions.rb
@@ -179,7 +194,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
194
  requirements:
180
195
  - - ">="
181
196
  - !ruby/object:Gem::Version
182
- version: '0'
197
+ version: 2.1.0
183
198
  required_rubygems_version: !ruby/object:Gem::Requirement
184
199
  requirements:
185
200
  - - ">="
@@ -187,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
202
  version: '0'
188
203
  requirements: []
189
204
  rubyforge_project:
190
- rubygems_version: 2.5.1
205
+ rubygems_version: 2.6.10
191
206
  signing_key:
192
207
  specification_version: 4
193
208
  summary: SynapsePay v3 Rest Native API Library
data/Gemfile.lock DELETED
@@ -1,61 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- synapse_pay_rest (2.0.0)
5
- rest-client (~> 2.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- ansi (1.5.0)
11
- builder (3.2.2)
12
- docile (1.1.5)
13
- domain_name (0.5.20160826)
14
- unf (>= 0.0.5, < 1.0.0)
15
- dotenv (2.1.1)
16
- faker (1.6.6)
17
- i18n (~> 0.5)
18
- http-cookie (1.0.3)
19
- domain_name (~> 0.5)
20
- i18n (0.7.0)
21
- json (1.8.3)
22
- mime-types (3.1)
23
- mime-types-data (~> 3.2015)
24
- mime-types-data (3.2016.0521)
25
- minitest (5.8.2)
26
- minitest-reporters (1.1.5)
27
- ansi
28
- builder
29
- minitest (>= 5.0)
30
- ruby-progressbar
31
- netrc (0.11.0)
32
- rake (10.4.2)
33
- rest-client (2.0.0)
34
- http-cookie (>= 1.0.2, < 2.0)
35
- mime-types (>= 1.16, < 4.0)
36
- netrc (~> 0.8)
37
- ruby-progressbar (1.7.5)
38
- simplecov (0.12.0)
39
- docile (~> 1.1.0)
40
- json (>= 1.8, < 3)
41
- simplecov-html (~> 0.10.0)
42
- simplecov-html (0.10.0)
43
- unf (0.1.4)
44
- unf_ext
45
- unf_ext (0.0.7.2)
46
-
47
- PLATFORMS
48
- ruby
49
-
50
- DEPENDENCIES
51
- bundler (~> 1.10)
52
- dotenv (~> 2.1.1)
53
- faker (~> 1.6.6)
54
- minitest (~> 5.8.2)
55
- minitest-reporters (~> 1.1.5)
56
- rake (~> 10.0)
57
- simplecov (~> 0.12.0)
58
- synapse_pay_rest!
59
-
60
- BUNDLED WITH
61
- 1.13.0