fidor_api 0.0.2 → 0.1.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +5 -3
- data/CHANGELOG.md +114 -0
- data/Gemfile +3 -2
- data/README.md +12 -10
- data/lib/fidor_api/account.rb +7 -10
- data/lib/fidor_api/amount_attributes.rb +23 -20
- data/lib/fidor_api/approval_required.rb +9 -0
- data/lib/fidor_api/auth.rb +1 -1
- data/lib/fidor_api/beneficiary/ach.rb +39 -0
- data/lib/fidor_api/beneficiary/base.rb +118 -0
- data/lib/fidor_api/beneficiary/generic.rb +24 -0
- data/lib/fidor_api/beneficiary/p2p_account_number.rb +14 -0
- data/lib/fidor_api/beneficiary/p2p_phone.rb +14 -0
- data/lib/fidor_api/beneficiary/p2p_username.rb +14 -0
- data/lib/fidor_api/beneficiary/swift.rb +35 -0
- data/lib/fidor_api/beneficiary/unknown.rb +16 -0
- data/lib/fidor_api/beneficiary/utility.rb +35 -0
- data/lib/fidor_api/beneficiary.rb +27 -0
- data/lib/fidor_api/card.rb +31 -48
- data/lib/fidor_api/card_limit_attribute.rb +52 -0
- data/lib/fidor_api/card_limits.rb +6 -34
- data/lib/fidor_api/client.rb +8 -2
- data/lib/fidor_api/collection.rb +15 -6
- data/lib/fidor_api/confirmable_action.rb +45 -0
- data/lib/fidor_api/connectivity/connection.rb +113 -0
- data/lib/fidor_api/connectivity/endpoint.rb +82 -0
- data/lib/fidor_api/connectivity/resource.rb +76 -0
- data/lib/fidor_api/connectivity.rb +17 -0
- data/lib/fidor_api/constants.rb +3 -0
- data/lib/fidor_api/customer.rb +41 -23
- data/lib/fidor_api/customers/confirmations.rb +19 -0
- data/lib/fidor_api/errors.rb +14 -3
- data/lib/fidor_api/message.rb +17 -18
- data/lib/fidor_api/msisdn.rb +1 -1
- data/lib/fidor_api/password.rb +30 -0
- data/lib/fidor_api/preauth.rb +5 -12
- data/lib/fidor_api/session_token.rb +20 -0
- data/lib/fidor_api/transaction.rb +5 -12
- data/lib/fidor_api/transfer/ach.rb +46 -0
- data/lib/fidor_api/transfer/bank_internal.rb +37 -0
- data/lib/fidor_api/transfer/base.rb +36 -0
- data/lib/fidor_api/transfer/fps.rb +56 -0
- data/lib/fidor_api/transfer/generic.rb +134 -0
- data/lib/fidor_api/transfer/internal.rb +53 -0
- data/lib/fidor_api/transfer/p2p_account_number.rb +45 -0
- data/lib/fidor_api/transfer/p2p_phone.rb +45 -0
- data/lib/fidor_api/transfer/p2p_username.rb +45 -0
- data/lib/fidor_api/transfer/sepa.rb +56 -0
- data/lib/fidor_api/transfer/swift.rb +49 -0
- data/lib/fidor_api/transfer/utility.rb +50 -0
- data/lib/fidor_api/transfer.rb +13 -186
- data/lib/fidor_api/user.rb +12 -11
- data/lib/fidor_api/version.rb +1 -1
- data/lib/fidor_api.rb +39 -22
- metadata +37 -4
- data/lib/fidor_api/resource.rb +0 -84
data/lib/fidor_api/card.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module FidorApi
|
2
|
-
|
3
|
-
class Card < Resource
|
2
|
+
class Card < Connectivity::Resource
|
4
3
|
extend ModelAttribute
|
5
4
|
extend AmountAttributes
|
5
|
+
include CardLimitAttribute
|
6
|
+
|
7
|
+
self.endpoint = Connectivity::Endpoint.new('/cards', :collection)
|
6
8
|
|
7
9
|
attribute :id, :integer
|
8
10
|
attribute :account_id, :string
|
@@ -16,79 +18,60 @@ module FidorApi
|
|
16
18
|
attribute :sms_notification, :boolean
|
17
19
|
attribute :payed, :boolean
|
18
20
|
attribute :state, :string
|
21
|
+
attribute :valid_until, :time
|
19
22
|
attribute :lock_reason, :string
|
20
23
|
attribute :disabled, :boolean
|
24
|
+
attribute :address, :json
|
21
25
|
attribute :created_at, :time
|
22
26
|
attribute :updated_at, :time
|
23
27
|
|
24
28
|
amount_attribute :balance
|
25
|
-
amount_attribute :atm_limit
|
26
|
-
amount_attribute :transaction_single_limit
|
27
|
-
amount_attribute :transaction_volume_limit
|
28
29
|
|
29
30
|
def self.required_attributes
|
30
|
-
|
31
|
+
%i(account_id type)
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
def self.all(access_token, options = {})
|
36
|
-
Collection.build(self, request(access_token: access_token, endpoint: "/cards", query_params: options).body)
|
34
|
+
def self.writeable_attributes
|
35
|
+
required_attributes + %i(pin address)
|
37
36
|
end
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
validates(*required_attributes, presence: true)
|
39
|
+
|
40
|
+
def activate
|
41
|
+
endpoint.for(self).put(action: 'activate')
|
42
|
+
true
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
44
|
-
|
45
|
+
def lock
|
46
|
+
endpoint.for(self).put(action: 'lock')
|
45
47
|
true
|
46
48
|
end
|
47
49
|
|
48
|
-
def
|
49
|
-
|
50
|
+
def unlock
|
51
|
+
endpoint.for(self).put(action: 'unlock')
|
50
52
|
true
|
51
53
|
end
|
52
54
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
55
|
+
def cancel(reason: 'lost')
|
56
|
+
case reason
|
57
|
+
when 'lost'
|
58
|
+
endpoint.for(self).put(action: 'cancel')
|
59
|
+
when 'stolen'
|
60
|
+
endpoint.for(self).put(action: 'block')
|
56
61
|
else
|
57
|
-
|
62
|
+
fail ArgumentError, "Unknown reason: #{reason.inspect}"
|
58
63
|
end
|
64
|
+
true
|
59
65
|
end
|
60
66
|
|
61
67
|
def as_json
|
62
|
-
attributes.slice
|
68
|
+
attributes.slice(*self.class.writeable_attributes)
|
63
69
|
end
|
64
70
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
"
|
69
|
-
end
|
70
|
-
|
71
|
-
module ClientSupport
|
72
|
-
def cards(options = {})
|
73
|
-
Card.all(token.access_token, options)
|
74
|
-
end
|
75
|
-
|
76
|
-
def card(id)
|
77
|
-
Card.find(token.access_token, id)
|
78
|
-
end
|
79
|
-
|
80
|
-
def lock_card(id)
|
81
|
-
Card.lock(token.access_token, id)
|
82
|
-
end
|
83
|
-
|
84
|
-
def unlock_card(id)
|
85
|
-
Card.unlock(token.access_token, id)
|
86
|
-
end
|
87
|
-
|
88
|
-
def build_card(attributes = {})
|
89
|
-
Card.new(attributes.merge(client: self))
|
90
|
-
end
|
71
|
+
# comfort shorthands for easier validations
|
72
|
+
%w(name line_1 line_2 city postal_code country).each do |field|
|
73
|
+
define_method("address_#{field}") { address.try :[], field }
|
74
|
+
define_method("address_#{field}=") { |val| self.address ||= {}; address[field] = val }
|
91
75
|
end
|
92
76
|
end
|
93
|
-
|
94
77
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module FidorApi
|
2
|
+
module CardLimitAttribute
|
3
|
+
def self.included(base)
|
4
|
+
base.attribute :limits, :json
|
5
|
+
base.validate :validate_limits
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(symbol, *args)
|
9
|
+
if m = symbol.to_s.match(/(.*)_limit$/)
|
10
|
+
limits[m[1]]
|
11
|
+
elsif m = symbol.to_s.match(/(.*)_limit=$/)
|
12
|
+
write_limit(m[1], args[0])
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to_missing?(symbol, include_all = false)
|
19
|
+
if symbol.to_s =~ /.*_limit=?$/
|
20
|
+
return true
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def write_limit(key, value)
|
29
|
+
self.limits ||= {}
|
30
|
+
# If the client is using BigDecimal, we will cast it to cents for him
|
31
|
+
if value.instance_of?(BigDecimal)
|
32
|
+
self.limits[key] = (value * 100.00).to_i
|
33
|
+
else
|
34
|
+
self.limits[key] = value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_limits
|
39
|
+
limits.each do |key, value|
|
40
|
+
if value.instance_of?(BigDecimal)
|
41
|
+
limits[key] = (value * 100.00).to_i
|
42
|
+
elsif !(value.class.name.in?(INTEGER_CLASSES) || value.instance_of?(NilClass))
|
43
|
+
errors.add(:"#{key}_limit", :not_an_integer)
|
44
|
+
next
|
45
|
+
end
|
46
|
+
if limits[key] < 0
|
47
|
+
errors.add(:"#{key}_limit", :greater_than_or_equal_to, count: 0)
|
48
|
+
end
|
49
|
+
end if limits
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,42 +1,14 @@
|
|
1
1
|
module FidorApi
|
2
|
-
|
3
|
-
class CardLimits < Resource
|
2
|
+
class CardLimits < Connectivity::Resource
|
4
3
|
extend ModelAttribute
|
5
|
-
|
6
|
-
|
7
|
-
attribute :id, :integer
|
8
|
-
amount_attribute :atm_limit
|
9
|
-
amount_attribute :transaction_single_limit
|
10
|
-
amount_attribute :transaction_volume_limit
|
11
|
-
|
12
|
-
def self.find(access_token, id)
|
13
|
-
attributes = request(access_token: access_token, endpoint: "/cards/#{id}/limits").body
|
14
|
-
attributes.merge!(id: id)
|
15
|
-
new(attributes)
|
16
|
-
end
|
4
|
+
include CardLimitAttribute
|
17
5
|
|
18
|
-
|
19
|
-
attributes = limits.merge(id: id)
|
6
|
+
self.endpoint = Connectivity::Endpoint.new('/cards/:id/limits', :resource)
|
20
7
|
|
21
|
-
|
22
|
-
record.set_attributes request(
|
23
|
-
method: :put,
|
24
|
-
access_token: access_token,
|
25
|
-
endpoint: "/cards/#{id}/limits",
|
26
|
-
body: record.as_json
|
27
|
-
).body
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
module ClientSupport
|
32
|
-
def card_limits(id)
|
33
|
-
CardLimits.find(token.access_token, id)
|
34
|
-
end
|
8
|
+
attribute :id, :integer
|
35
9
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
10
|
+
def as_json
|
11
|
+
attributes.slice(:limits)
|
39
12
|
end
|
40
13
|
end
|
41
|
-
|
42
14
|
end
|
data/lib/fidor_api/client.rb
CHANGED
@@ -6,15 +6,21 @@ module FidorApi
|
|
6
6
|
attr_accessor :token
|
7
7
|
|
8
8
|
include Account::ClientSupport
|
9
|
-
include
|
10
|
-
include
|
9
|
+
include Beneficiary::ClientSupport
|
10
|
+
include Beneficiary::ACH::ClientSupport
|
11
|
+
include ConfirmableAction::ClientSupport
|
11
12
|
include Customer::ClientSupport
|
12
13
|
include Message::ClientSupport
|
13
14
|
include Preauth::ClientSupport
|
15
|
+
include SessionToken::ClientSupport
|
14
16
|
include Transaction::ClientSupport
|
17
|
+
include Transfer::ACH::ClientSupport
|
15
18
|
include Transfer::Internal::ClientSupport
|
16
19
|
include Transfer::SEPA::ClientSupport
|
17
20
|
include Transfer::FPS::ClientSupport
|
21
|
+
include Transfer::P2pAccountNumber::ClientSupport
|
22
|
+
include Transfer::P2pPhone::ClientSupport
|
23
|
+
include Transfer::P2pUsername::ClientSupport
|
18
24
|
include User::ClientSupport
|
19
25
|
end
|
20
26
|
|
data/lib/fidor_api/collection.rb
CHANGED
@@ -5,18 +5,27 @@ module FidorApi
|
|
5
5
|
include Enumerable
|
6
6
|
|
7
7
|
attr_accessor :records
|
8
|
-
attr_accessor :total_pages, :current_page, :limit_value
|
8
|
+
attr_accessor :total_pages, :current_page, :limit_value, :total_entries
|
9
9
|
|
10
10
|
def self.build(klass, response)
|
11
11
|
new.tap do |object|
|
12
12
|
data = response["data"]
|
13
13
|
collection = response["collection"]
|
14
14
|
|
15
|
-
object.records = data.map
|
15
|
+
object.records = data.map do |record|
|
16
|
+
class_to_instantiate = if block_given?
|
17
|
+
yield(record)
|
18
|
+
else
|
19
|
+
klass
|
20
|
+
end
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
class_to_instantiate.new(record)
|
23
|
+
end
|
24
|
+
|
25
|
+
object.total_pages = collection["total_pages"]
|
26
|
+
object.current_page = collection["current_page"]
|
27
|
+
object.limit_value = collection["per_page"]
|
28
|
+
object.total_entries = collection["total_entries"]
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
@@ -34,4 +43,4 @@ module FidorApi
|
|
34
43
|
end
|
35
44
|
end
|
36
45
|
|
37
|
-
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module FidorApi
|
2
|
+
class ConfirmableAction < Connectivity::Resource
|
3
|
+
extend ModelAttribute
|
4
|
+
|
5
|
+
self.endpoint = Connectivity::Endpoint.new('/confirmable/actions', :collection)
|
6
|
+
|
7
|
+
attribute :id, :string
|
8
|
+
attribute :type, :string
|
9
|
+
attribute :message, :string
|
10
|
+
attribute :steps_left, :json
|
11
|
+
attribute :steps_completed, :json
|
12
|
+
attribute :resource, :json
|
13
|
+
attribute :succeeded_at, :time
|
14
|
+
attribute :failed_at, :time
|
15
|
+
attribute :errored_at, :time
|
16
|
+
attribute :created_at, :time
|
17
|
+
attribute :updated_at, :time
|
18
|
+
|
19
|
+
attribute :otp, :string
|
20
|
+
attribute :approval, :string
|
21
|
+
|
22
|
+
def refresh
|
23
|
+
endpoint.for(self).put(action: "refresh")
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClientSupport
|
28
|
+
def confirmable_actions(options = {})
|
29
|
+
ConfirmableAction.all
|
30
|
+
end
|
31
|
+
|
32
|
+
def confirmable_action(id)
|
33
|
+
ConfirmableAction.find(id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_confirmable_action(id, attributes)
|
37
|
+
ConfirmableAction.new(attributes.merge(id: id)).save
|
38
|
+
end
|
39
|
+
|
40
|
+
def refresh_confirmable_action(id)
|
41
|
+
ConfirmableAction.new(id: id).refresh
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module FidorApi
|
2
|
+
module Connectivity
|
3
|
+
module Connection
|
4
|
+
extend self
|
5
|
+
|
6
|
+
Response = Struct.new(:status, :headers, :raw_body) do
|
7
|
+
def body
|
8
|
+
if headers["content-type"] =~ /json/
|
9
|
+
JSON.parse(raw_body)
|
10
|
+
else
|
11
|
+
raw_body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, options={})
|
17
|
+
request(:get, path, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, options={})
|
21
|
+
request(:post, path, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def put(path, options={})
|
25
|
+
request(:put, path, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(path, options={})
|
29
|
+
request(:delete, path, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_token(token)
|
33
|
+
self.access_token = token
|
34
|
+
yield
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def request(method, path, options={})
|
40
|
+
options.reverse_merge! version: 1, access_token: Connectivity.access_token
|
41
|
+
response = faraday.public_send(method, [FidorApi.configuration.api_path, path].compact.join) do |request|
|
42
|
+
request.params = options[:query_params] if options[:query_params]
|
43
|
+
request.headers = {}
|
44
|
+
if options[:access_token]
|
45
|
+
request.headers["Authorization"] = "Bearer #{options[:access_token]}"
|
46
|
+
else
|
47
|
+
request.headers["Authorization"] = tokenless_http_basic_header
|
48
|
+
end
|
49
|
+
request.headers["Accept"] = "application/vnd.fidor.de; version=#{options[:version]},text/json"
|
50
|
+
request.headers["Content-Type"] = "application/json"
|
51
|
+
if options[:body]
|
52
|
+
if options[:body].is_a?(String)
|
53
|
+
request.body = options[:body]
|
54
|
+
elsif options[:body].respond_to?(:to_json)
|
55
|
+
request.body = options[:body].to_json
|
56
|
+
else
|
57
|
+
fail ArgumentError, "unhandled body type #{options[:body].inspect}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if response.status == 303 && URI.parse(response.headers["Location"]).path =~ /^(\/fidor_api)?\/confirmable\//
|
62
|
+
confirmable_action = ConfirmableAction.new(id: URI.parse(response.headers["Location"]).path.split("/").last)
|
63
|
+
raise ApprovalRequired.new(confirmable_action)
|
64
|
+
end
|
65
|
+
Response.new(response.status, response.headers, response.body)
|
66
|
+
rescue Faraday::Error::ClientError => e
|
67
|
+
log :info, "Error (#{e.class.name}): #{e.to_s}\nStatus: #{e.response[:status]}"
|
68
|
+
log :debug, "Header: #{e.response[:header]}\nBody: #{e.response[:body]}" if e.response[:status] != 500
|
69
|
+
case e.response[:status]
|
70
|
+
when 401
|
71
|
+
raise UnauthorizedTokenError
|
72
|
+
when 403
|
73
|
+
body = JSON.parse(e.response[:body])
|
74
|
+
raise ForbiddenError.new(body["message"], body["code"], body["key"])
|
75
|
+
when 422
|
76
|
+
body = JSON.parse(e.response[:body])
|
77
|
+
raise ValidationError.new(body["message"], body["errors"], body["key"])
|
78
|
+
else
|
79
|
+
raise ClientError.new(e.response[:body])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def log(level, message)
|
84
|
+
return unless FidorApi.configuration.logging
|
85
|
+
FidorApi.configuration.logger.public_send(level, message)
|
86
|
+
end
|
87
|
+
|
88
|
+
def logger_type
|
89
|
+
if defined?(Faraday::DetailedLogger)
|
90
|
+
:detailed_logger
|
91
|
+
else
|
92
|
+
:logger
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def tokenless_http_basic_header
|
97
|
+
@tokenless_http_basic_header ||= begin
|
98
|
+
base64 = Base64.strict_encode64("#{FidorApi.configuration.htauth_user}:#{FidorApi.configuration.htauth_password}")
|
99
|
+
"Basic #{base64}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def faraday
|
104
|
+
@faraday ||= Faraday.new(url: FidorApi.configuration.api_url, ssl: { verify: FidorApi.configuration.verify_ssl }) do |config|
|
105
|
+
config.request :url_encoded
|
106
|
+
config.response logger_type, FidorApi.configuration.logger if FidorApi.configuration.logging
|
107
|
+
config.response :raise_error
|
108
|
+
config.adapter Faraday.default_adapter
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module FidorApi
|
2
|
+
module Connectivity
|
3
|
+
class Endpoint
|
4
|
+
attr_reader :collection, :resource, :version, :tokenless
|
5
|
+
|
6
|
+
def initialize(path, mode, version: '1', tokenless: false)
|
7
|
+
@path = path
|
8
|
+
@version = version
|
9
|
+
@tokenless = tokenless
|
10
|
+
|
11
|
+
case mode
|
12
|
+
when :collection
|
13
|
+
@collection = path
|
14
|
+
@resource = "#{path}/:id"
|
15
|
+
when :resource
|
16
|
+
@resource = path
|
17
|
+
else
|
18
|
+
fail ArgumentError, "mode #{mode.inspect} must be resource or collection"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Context
|
23
|
+
def initialize(endpoint, object)
|
24
|
+
@endpoint = endpoint
|
25
|
+
@object = object
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(target: :resource, action: nil, query_params: nil, tokenless: nil)
|
29
|
+
request :get, target, action, query_params: query_params, tokenless: tokenless
|
30
|
+
end
|
31
|
+
|
32
|
+
def post(target: :collection, action: nil, payload: nil, tokenless: nil)
|
33
|
+
request :post, target, action, body: payload, tokenless: tokenless
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(target: :resource, action: nil, payload: nil, tokenless: nil)
|
37
|
+
request :put, target, action, body: payload, tokenless: tokenless
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(target: :resource, action: nil, tokenless: nil)
|
41
|
+
request :delete, target, action, tokenless: tokenless
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def request(method, target, action, options = {})
|
47
|
+
options.reverse_merge! version: @endpoint.version
|
48
|
+
options[:access_token] = nil if options[:tokenless] || @endpoint.tokenless
|
49
|
+
Connection.public_send(method, send("#{target}_path", action), options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def resource_path(action = nil)
|
53
|
+
interpolate(@endpoint.resource, action)
|
54
|
+
end
|
55
|
+
|
56
|
+
def collection_path(action = nil)
|
57
|
+
interpolate(@endpoint.collection, action)
|
58
|
+
end
|
59
|
+
|
60
|
+
def interpolate(path, suffix = nil)
|
61
|
+
[path, suffix].compact.join('/').gsub(/:(\w+)/) do |m|
|
62
|
+
fetch_option $1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_option(name)
|
67
|
+
if @object.kind_of? Hash
|
68
|
+
@object[name]
|
69
|
+
elsif @object.class.name.in?(INTEGER_CLASSES) || @object.kind_of?(String)
|
70
|
+
@object
|
71
|
+
elsif @object.respond_to? name
|
72
|
+
@object.public_send name
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def for(object)
|
78
|
+
Context.new(self, object)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module FidorApi
|
2
|
+
module Connectivity
|
3
|
+
class Resource
|
4
|
+
include ActiveModel::Model
|
5
|
+
extend ModelAttribute
|
6
|
+
|
7
|
+
class_attribute :endpoint
|
8
|
+
|
9
|
+
attr_accessor :error_keys
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def find(id)
|
13
|
+
new endpoint.for(id).get.body.reverse_merge(id: id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def all(options = {})
|
17
|
+
FidorApi::Collection.build self, endpoint.for(self).get(target: :collection, query_params: options).body
|
18
|
+
end
|
19
|
+
|
20
|
+
def model_name
|
21
|
+
ActiveModel::Name.new(self, nil, self.name.sub("FidorApi::", ""))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(attributes = {})
|
26
|
+
set_attributes attributes
|
27
|
+
end
|
28
|
+
|
29
|
+
def reload
|
30
|
+
set_attributes endpoint.for(self).get.body
|
31
|
+
end
|
32
|
+
|
33
|
+
def persisted?
|
34
|
+
id.present?
|
35
|
+
end
|
36
|
+
|
37
|
+
def save
|
38
|
+
if valid?
|
39
|
+
set_attributes(persisted? ? remote_update.body : remote_create.body)
|
40
|
+
true
|
41
|
+
else
|
42
|
+
false
|
43
|
+
end
|
44
|
+
rescue ValidationError => e
|
45
|
+
self.error_keys = e.error_keys
|
46
|
+
map_errors(e.fields)
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_attributes(attributes={})
|
51
|
+
set_attributes attributes
|
52
|
+
valid? and remote_update attributes.keys
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def remote_create
|
58
|
+
endpoint.for(self).post(payload: self.as_json)
|
59
|
+
end
|
60
|
+
|
61
|
+
def remote_update(*attributes)
|
62
|
+
payload = self.as_json.with_indifferent_access
|
63
|
+
payload.slice!(*attributes.flatten) if attributes.present?
|
64
|
+
endpoint.for(self).put(payload: payload)
|
65
|
+
end
|
66
|
+
|
67
|
+
def map_errors(fields)
|
68
|
+
fields.each do |hash|
|
69
|
+
hash.symbolize_keys!
|
70
|
+
field = hash[:field].to_sym
|
71
|
+
errors.add(field, hash[:message], hash) if respond_to?(field) || field == :base
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FidorApi
|
2
|
+
module Connectivity
|
3
|
+
extend self
|
4
|
+
|
5
|
+
autoload :Connection, 'fidor_api/connectivity/connection'
|
6
|
+
autoload :Resource, 'fidor_api/connectivity/resource'
|
7
|
+
autoload :Endpoint, 'fidor_api/connectivity/endpoint'
|
8
|
+
|
9
|
+
def access_token=(val)
|
10
|
+
Thread.current[:fidor_api_access_token] = val
|
11
|
+
end
|
12
|
+
|
13
|
+
def access_token
|
14
|
+
Thread.current[:fidor_api_access_token]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|