fidor_api 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|