restforce 1.5.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of restforce might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +60 -0
- data/.rubocop_todo.yml +117 -0
- data/.travis.yml +3 -5
- data/CHANGELOG.md +6 -0
- data/README.md +2 -0
- data/Rakefile +1 -1
- data/lib/restforce/abstract_client.rb +1 -1
- data/lib/restforce/attachment.rb +1 -3
- data/lib/restforce/concerns/api.rb +22 -17
- data/lib/restforce/concerns/authentication.rb +4 -3
- data/lib/restforce/concerns/base.rb +42 -31
- data/lib/restforce/concerns/caching.rb +1 -3
- data/lib/restforce/concerns/canvas.rb +0 -2
- data/lib/restforce/concerns/connection.rb +18 -12
- data/lib/restforce/concerns/picklists.rb +10 -10
- data/lib/restforce/concerns/streaming.rb +9 -4
- data/lib/restforce/concerns/verbs.rb +0 -2
- data/lib/restforce/config.rb +19 -13
- data/lib/restforce/data/client.rb +8 -1
- data/lib/restforce/mash.rb +6 -10
- data/lib/restforce/middleware.rb +3 -1
- data/lib/restforce/middleware/authentication.rb +21 -7
- data/lib/restforce/middleware/authentication/password.rb +5 -9
- data/lib/restforce/middleware/authentication/token.rb +4 -8
- data/lib/restforce/middleware/authorization.rb +0 -3
- data/lib/restforce/middleware/caching.rb +4 -4
- data/lib/restforce/middleware/instance_url.rb +3 -5
- data/lib/restforce/middleware/logger.rb +7 -7
- data/lib/restforce/middleware/mashify.rb +2 -3
- data/lib/restforce/middleware/multipart.rb +15 -8
- data/lib/restforce/middleware/raise_error.rb +2 -1
- data/lib/restforce/patches/parts.rb +2 -3
- data/lib/restforce/signed_request.rb +2 -2
- data/lib/restforce/sobject.rb +1 -3
- data/lib/restforce/tooling/client.rb +1 -3
- data/lib/restforce/upload_io.rb +1 -3
- data/lib/restforce/version.rb +1 -1
- data/restforce.gemspec +7 -4
- data/spec/integration/abstract_client_spec.rb +123 -75
- data/spec/integration/data/client_spec.rb +24 -12
- data/spec/spec_helper.rb +2 -2
- data/spec/support/client_integration.rb +23 -17
- data/spec/support/concerns.rb +2 -2
- data/spec/support/event_machine.rb +3 -3
- data/spec/support/fixture_helpers.rb +16 -12
- data/spec/support/middleware.rb +16 -8
- data/spec/unit/abstract_client_spec.rb +1 -1
- data/spec/unit/attachment_spec.rb +2 -1
- data/spec/unit/collection_spec.rb +13 -4
- data/spec/unit/concerns/api_spec.rb +15 -13
- data/spec/unit/concerns/authentication_spec.rb +20 -17
- data/spec/unit/concerns/base_spec.rb +2 -2
- data/spec/unit/concerns/caching_spec.rb +2 -2
- data/spec/unit/concerns/canvas_spec.rb +3 -3
- data/spec/unit/concerns/connection_spec.rb +6 -7
- data/spec/unit/concerns/streaming_spec.rb +8 -8
- data/spec/unit/config_spec.rb +6 -6
- data/spec/unit/data/client_spec.rb +1 -1
- data/spec/unit/mash_spec.rb +1 -1
- data/spec/unit/middleware/authentication/password_spec.rb +14 -12
- data/spec/unit/middleware/authentication/token_spec.rb +12 -10
- data/spec/unit/middleware/authentication_spec.rb +15 -11
- data/spec/unit/middleware/authorization_spec.rb +1 -1
- data/spec/unit/middleware/gzip_spec.rb +1 -1
- data/spec/unit/middleware/instance_url_spec.rb +2 -2
- data/spec/unit/middleware/mashify_spec.rb +2 -2
- data/spec/unit/middleware/raise_error_spec.rb +23 -7
- data/spec/unit/sobject_spec.rb +16 -9
- data/spec/unit/tooling/client_spec.rb +1 -1
- metadata +23 -5
@@ -1,7 +1,6 @@
|
|
1
1
|
module Restforce
|
2
2
|
module Concerns
|
3
3
|
module Caching
|
4
|
-
|
5
4
|
# Public: Runs the block with caching disabled.
|
6
5
|
#
|
7
6
|
# block - A query/describe/etc.
|
@@ -14,13 +13,12 @@ module Restforce
|
|
14
13
|
options.delete(:use_cache)
|
15
14
|
end
|
16
15
|
|
17
|
-
|
16
|
+
private
|
18
17
|
|
19
18
|
# Internal: Cache to use for the caching middleware
|
20
19
|
def cache
|
21
20
|
options[:cache]
|
22
21
|
end
|
23
|
-
|
24
22
|
end
|
25
23
|
end
|
26
24
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Restforce
|
2
2
|
module Concerns
|
3
3
|
module Connection
|
4
|
-
|
5
4
|
# Public: The Faraday::Builder instance used for the middleware stack. This
|
6
5
|
# can be used to insert an custom middleware.
|
7
6
|
#
|
@@ -16,25 +15,31 @@ module Restforce
|
|
16
15
|
end
|
17
16
|
alias_method :builder, :middleware
|
18
17
|
|
19
|
-
|
18
|
+
private
|
20
19
|
|
21
20
|
# Internal: Internal faraday connection where all requests go through
|
22
21
|
def connection
|
23
|
-
@connection ||= Faraday.new(options[:instance_url],
|
22
|
+
@connection ||= Faraday.new(options[:instance_url],
|
23
|
+
connection_options) do |builder|
|
24
24
|
# Parses JSON into Hashie::Mash structures.
|
25
|
-
|
25
|
+
unless (options[:mashify] == false)
|
26
|
+
builder.use Restforce::Middleware::Mashify, self, options
|
27
|
+
end
|
28
|
+
|
26
29
|
# Handles multipart file uploads for blobs.
|
27
30
|
builder.use Restforce::Middleware::Multipart
|
28
31
|
# Converts the request into JSON.
|
29
32
|
builder.request :json
|
30
33
|
# Handles reauthentication for 403 responses.
|
31
|
-
|
34
|
+
if authentication_middleware
|
35
|
+
builder.use authentication_middleware, self, options
|
36
|
+
end
|
32
37
|
# Sets the oauth token in the headers.
|
33
38
|
builder.use Restforce::Middleware::Authorization, self, options
|
34
39
|
# Ensures the instance url is set.
|
35
40
|
builder.use Restforce::Middleware::InstanceURL, self, options
|
36
41
|
# Parses returned JSON response into a hash.
|
37
|
-
builder.response :json, :
|
42
|
+
builder.response :json, content_type: /\bjson$/
|
38
43
|
# Caches GET requests.
|
39
44
|
builder.use Restforce::Middleware::Caching, cache, options if cache
|
40
45
|
# Follows 30x redirects.
|
@@ -42,7 +47,9 @@ module Restforce
|
|
42
47
|
# Raises errors for 40x responses.
|
43
48
|
builder.use Restforce::Middleware::RaiseError
|
44
49
|
# Log request/responses
|
45
|
-
builder.use Restforce::Middleware::Logger,
|
50
|
+
builder.use Restforce::Middleware::Logger,
|
51
|
+
Restforce.configuration.logger,
|
52
|
+
options if Restforce.log?
|
46
53
|
# Compress/Decompress the request/response
|
47
54
|
builder.use Restforce::Middleware::Gzip, self, options
|
48
55
|
|
@@ -56,10 +63,10 @@ module Restforce
|
|
56
63
|
|
57
64
|
# Internal: Faraday Connection options
|
58
65
|
def connection_options
|
59
|
-
{ :
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:
|
66
|
+
{ request: {
|
67
|
+
timeout: options[:timeout],
|
68
|
+
open_timeout: options[:timeout] },
|
69
|
+
proxy: options[:proxy_uri]
|
63
70
|
}
|
64
71
|
end
|
65
72
|
|
@@ -68,7 +75,6 @@ module Restforce
|
|
68
75
|
def mashify?
|
69
76
|
middleware.handlers.index(Restforce::Middleware::Mashify)
|
70
77
|
end
|
71
|
-
|
72
78
|
end
|
73
79
|
end
|
74
80
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Restforce
|
2
2
|
module Concerns
|
3
3
|
module Picklists
|
4
|
-
|
5
4
|
# Public: Get the available picklist values for a picklist or multipicklist field.
|
6
5
|
#
|
7
6
|
# sobject - The String name of the sobject.
|
@@ -27,18 +26,18 @@ module Restforce
|
|
27
26
|
PicklistValues.new(describe(sobject)['fields'], field, options)
|
28
27
|
end
|
29
28
|
|
30
|
-
|
29
|
+
private
|
31
30
|
|
32
31
|
class PicklistValues < Array
|
33
|
-
|
34
32
|
def initialize(fields, field, options = {})
|
35
|
-
@fields
|
33
|
+
@fields = fields
|
34
|
+
@field = field
|
36
35
|
@valid_for = options.delete(:valid_for)
|
37
36
|
raise "#{field} is not a dependent picklist" if @valid_for && !dependent?
|
38
37
|
replace(picklist_values)
|
39
38
|
end
|
40
39
|
|
41
|
-
|
40
|
+
private
|
42
41
|
|
43
42
|
attr_reader :fields
|
44
43
|
|
@@ -60,7 +59,8 @@ module Restforce
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def controlling_picklist
|
63
|
-
@_controlling_picklist ||= controlling_field['picklistValues'].
|
62
|
+
@_controlling_picklist ||= controlling_field['picklistValues'].
|
63
|
+
find { |picklist_entry| picklist_entry['value'] == @valid_for }
|
64
64
|
end
|
65
65
|
|
66
66
|
def index
|
@@ -77,14 +77,14 @@ module Restforce
|
|
77
77
|
|
78
78
|
# Returns true if the picklist entry is valid for the controlling picklist.
|
79
79
|
#
|
80
|
-
# See http://www.salesforce.com/us/developer/docs/api/Content/
|
80
|
+
# See http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_des
|
81
|
+
# cribesobjects_describesobjectresult.htm
|
81
82
|
def valid?(picklist_entry)
|
82
|
-
valid_for = picklist_entry['validFor'].ljust(16, 'A').unpack('m').first.
|
83
|
+
valid_for = picklist_entry['validFor'].ljust(16, 'A').unpack('m').first.
|
84
|
+
unpack('q*')
|
83
85
|
(valid_for[index >> 3] & (0x80 >> index % 8)) != 0
|
84
86
|
end
|
85
|
-
|
86
87
|
end
|
87
|
-
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Restforce
|
2
2
|
module Concerns
|
3
3
|
module Streaming
|
4
|
-
|
5
4
|
# Public: Subscribe to a PushTopic
|
6
5
|
#
|
7
6
|
# channels - The name of the PushTopic channel(s) to subscribe to.
|
@@ -14,19 +13,25 @@ module Restforce
|
|
14
13
|
|
15
14
|
# Public: Faye client to use for subscribing to PushTopics
|
16
15
|
def faye
|
17
|
-
|
18
|
-
|
16
|
+
unless options[:instance_url]
|
17
|
+
raise 'Instance URL missing. Call .authenticate! first.'
|
18
|
+
end
|
19
|
+
|
20
|
+
url = "#{options[:instance_url]}/cometd/#{options[:api_version]}"
|
21
|
+
|
22
|
+
@faye ||= Faye::Client.new(url).tap do |client|
|
19
23
|
client.set_header 'Authorization', "OAuth #{options[:oauth_token]}"
|
24
|
+
|
20
25
|
client.bind 'transport:down' do
|
21
26
|
Restforce.log "[COMETD DOWN]"
|
22
27
|
client.set_header 'Authorization', "OAuth #{authenticate!.access_token}"
|
23
28
|
end
|
29
|
+
|
24
30
|
client.bind 'transport:up' do
|
25
31
|
Restforce.log "[COMETD UP]"
|
26
32
|
end
|
27
33
|
end
|
28
34
|
end
|
29
|
-
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Restforce
|
2
2
|
module Concerns
|
3
3
|
module Verbs
|
4
|
-
|
5
4
|
# Internal: Define methods to handle a verb.
|
6
5
|
#
|
7
6
|
# verbs - A list of verbs to define methods for.
|
@@ -62,7 +61,6 @@ module Restforce
|
|
62
61
|
send(verb, *args, &block)
|
63
62
|
end
|
64
63
|
end
|
65
|
-
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
data/lib/restforce/config.rb
CHANGED
@@ -45,7 +45,9 @@ module Restforce
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def initialize(configuration, name, options = {})
|
48
|
-
@configuration
|
48
|
+
@configuration = configuration
|
49
|
+
@name = name
|
50
|
+
@options = options
|
49
51
|
@default = options.fetch(:default, nil)
|
50
52
|
end
|
51
53
|
|
@@ -55,7 +57,8 @@ module Restforce
|
|
55
57
|
self
|
56
58
|
end
|
57
59
|
|
58
|
-
|
60
|
+
private
|
61
|
+
|
59
62
|
attr_reader :default
|
60
63
|
alias_method :default_provided?, :default
|
61
64
|
|
@@ -68,7 +71,10 @@ module Restforce
|
|
68
71
|
our_name = name
|
69
72
|
configuration.send :define_method, our_name do
|
70
73
|
instance_variable_get(:"@#{our_name}") ||
|
71
|
-
instance_variable_set(
|
74
|
+
instance_variable_set(
|
75
|
+
:"@#{our_name}",
|
76
|
+
our_default.respond_to?(:call) ? our_default.call : our_default
|
77
|
+
)
|
72
78
|
end
|
73
79
|
end
|
74
80
|
end
|
@@ -82,26 +88,26 @@ module Restforce
|
|
82
88
|
end
|
83
89
|
end
|
84
90
|
|
85
|
-
option :api_version, :
|
91
|
+
option :api_version, default: '26.0'
|
86
92
|
|
87
93
|
# The username to use during login.
|
88
|
-
option :username, :
|
94
|
+
option :username, default: lambda { ENV['SALESFORCE_USERNAME'] }
|
89
95
|
|
90
96
|
# The password to use during login.
|
91
|
-
option :password, :
|
97
|
+
option :password, default: lambda { ENV['SALESFORCE_PASSWORD'] }
|
92
98
|
|
93
99
|
# The security token to use during login.
|
94
|
-
option :security_token, :
|
100
|
+
option :security_token, default: lambda { ENV['SALESFORCE_SECURITY_TOKEN'] }
|
95
101
|
|
96
102
|
# The OAuth client id
|
97
|
-
option :client_id, :
|
103
|
+
option :client_id, default: lambda { ENV['SALESFORCE_CLIENT_ID'] }
|
98
104
|
|
99
105
|
# The OAuth client secret
|
100
|
-
option :client_secret, :
|
106
|
+
option :client_secret, default: lambda { ENV['SALESFORCE_CLIENT_SECRET'] }
|
101
107
|
|
102
108
|
# Set this to true if you're authenticating with a Sandbox instance.
|
103
109
|
# Defaults to false.
|
104
|
-
option :host, :
|
110
|
+
option :host, default: lambda { ENV['SALESFORCE_HOST'] || 'login.salesforce.com' }
|
105
111
|
|
106
112
|
option :oauth_token
|
107
113
|
option :refresh_token
|
@@ -112,7 +118,7 @@ module Restforce
|
|
112
118
|
option :cache
|
113
119
|
|
114
120
|
# The number of times reauthentication should be tried before failing.
|
115
|
-
option :authentication_retries, :
|
121
|
+
option :authentication_retries, default: 3
|
116
122
|
|
117
123
|
# Set to true if you want responses from Salesforce to be gzip compressed.
|
118
124
|
option :compress
|
@@ -125,10 +131,10 @@ module Restforce
|
|
125
131
|
option :timeout
|
126
132
|
|
127
133
|
# Faraday adapter to use. Defaults to Faraday.default_adapter.
|
128
|
-
option :adapter, :
|
134
|
+
option :adapter, default: lambda { Faraday.default_adapter }
|
129
135
|
|
130
136
|
# TODO: Rename this to `SALESFORCE_PROXY_URI` in next major version
|
131
|
-
option :proxy_uri, :
|
137
|
+
option :proxy_uri, default: lambda { ENV['PROXY_URI'] }
|
132
138
|
|
133
139
|
# A Proc that is called with the response body after a successful authentication.
|
134
140
|
option :authentication_callback
|
@@ -11,7 +11,14 @@ module Restforce
|
|
11
11
|
#
|
12
12
|
# Returns the url to the resource.
|
13
13
|
def url(resource)
|
14
|
-
|
14
|
+
resource_name_for_url =
|
15
|
+
if resource.respond_to?(:to_sparam)
|
16
|
+
resource.to_sparam
|
17
|
+
else
|
18
|
+
resource
|
19
|
+
end
|
20
|
+
|
21
|
+
"#{instance_url}/#{resource_name_for_url}"
|
15
22
|
end
|
16
23
|
end
|
17
24
|
end
|
data/lib/restforce/mash.rb
CHANGED
@@ -2,15 +2,13 @@ require 'hashie/mash'
|
|
2
2
|
|
3
3
|
module Restforce
|
4
4
|
class Mash < Hashie::Mash
|
5
|
-
|
6
5
|
class << self
|
7
|
-
|
8
6
|
# Pass in an Array or Hash and it will be recursively converted into the
|
9
7
|
# appropriate Restforce::Collection, Restforce::SObject and
|
10
8
|
# Restforce::Mash objects.
|
11
9
|
def build(val, client)
|
12
10
|
if val.is_a?(Array)
|
13
|
-
val.collect { |
|
11
|
+
val.collect { |a_val| self.build(a_val, client) }
|
14
12
|
elsif val.is_a?(Hash)
|
15
13
|
self.klass(val).new(val, client)
|
16
14
|
else
|
@@ -21,11 +19,11 @@ module Restforce
|
|
21
19
|
# When passed a hash, it will determine what class is appropriate to
|
22
20
|
# represent the data.
|
23
21
|
def klass(val)
|
24
|
-
if val.
|
22
|
+
if val.key? 'records'
|
25
23
|
# When the hash has a records key, it should be considered a collection
|
26
24
|
# of sobject records.
|
27
25
|
Restforce::Collection
|
28
|
-
elsif val.
|
26
|
+
elsif val.key? 'attributes'
|
29
27
|
if val['attributes']['type'] == 'Attachment'
|
30
28
|
Restforce::Attachment
|
31
29
|
else
|
@@ -38,7 +36,6 @@ module Restforce
|
|
38
36
|
Restforce::Mash
|
39
37
|
end
|
40
38
|
end
|
41
|
-
|
42
39
|
end
|
43
40
|
|
44
41
|
def initialize(source_hash = nil, client = nil, default = nil, &blk)
|
@@ -50,8 +47,8 @@ module Restforce
|
|
50
47
|
def dup
|
51
48
|
self.class.new(self, @client, self.default)
|
52
49
|
end
|
53
|
-
|
54
|
-
def convert_value(val, duping=false)
|
50
|
+
|
51
|
+
def convert_value(val, duping = false)
|
55
52
|
case val
|
56
53
|
when self.class
|
57
54
|
val.dup
|
@@ -59,11 +56,10 @@ module Restforce
|
|
59
56
|
val = val.dup if duping
|
60
57
|
self.class.klass(val).new(val, @client)
|
61
58
|
when Array
|
62
|
-
val.collect{ |e| convert_value(e) }
|
59
|
+
val.collect { |e| convert_value(e) }
|
63
60
|
else
|
64
61
|
val
|
65
62
|
end
|
66
63
|
end
|
67
|
-
|
68
64
|
end
|
69
65
|
end
|
data/lib/restforce/middleware.rb
CHANGED
@@ -13,7 +13,9 @@ module Restforce
|
|
13
13
|
autoload :Gzip, 'restforce/middleware/gzip'
|
14
14
|
|
15
15
|
def initialize(app, client, options)
|
16
|
-
@app
|
16
|
+
@app = app
|
17
|
+
@client = client
|
18
|
+
@options = options
|
17
19
|
end
|
18
20
|
|
19
21
|
# Internal: Proxy to the client.
|
@@ -21,10 +21,18 @@ module Restforce
|
|
21
21
|
response = connection.post '/services/oauth2/token' do |req|
|
22
22
|
req.body = encode_www_form(params)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
|
+
if response.status != 200
|
26
|
+
raise Restforce::AuthenticationError, error_message(response)
|
27
|
+
end
|
28
|
+
|
25
29
|
@options[:instance_url] = response.body['instance_url']
|
26
30
|
@options[:oauth_token] = response.body['access_token']
|
27
|
-
|
31
|
+
|
32
|
+
if @options[:authentication_callback]
|
33
|
+
@options[:authentication_callback].call(response.body)
|
34
|
+
end
|
35
|
+
|
28
36
|
response.body
|
29
37
|
end
|
30
38
|
|
@@ -39,7 +47,11 @@ module Restforce
|
|
39
47
|
builder.use Faraday::Request::UrlEncoded
|
40
48
|
builder.use Restforce::Middleware::Mashify, nil, @options
|
41
49
|
builder.response :json
|
42
|
-
|
50
|
+
|
51
|
+
builder.use Restforce::Middleware::Logger,
|
52
|
+
Restforce.configuration.logger,
|
53
|
+
@options if Restforce.log?
|
54
|
+
|
43
55
|
builder.adapter Faraday.default_adapter
|
44
56
|
end
|
45
57
|
end
|
@@ -56,16 +68,18 @@ module Restforce
|
|
56
68
|
URI.encode_www_form(params)
|
57
69
|
else
|
58
70
|
params.map do |k, v|
|
59
|
-
k
|
71
|
+
k = CGI.escape(k.to_s)
|
72
|
+
v = CGI.escape(v.to_s)
|
60
73
|
"#{k}=#{v}"
|
61
74
|
end.join('&')
|
62
75
|
end
|
63
76
|
end
|
64
77
|
|
65
|
-
|
78
|
+
private
|
79
|
+
|
66
80
|
def faraday_options
|
67
|
-
{ :
|
68
|
-
:
|
81
|
+
{ url: "https://#{@options[:host]}",
|
82
|
+
proxy: @options[:proxy_uri] }.reject { |k, v| v.nil? }
|
69
83
|
end
|
70
84
|
end
|
71
85
|
end
|