sfmc-fuelsdk-ruby 1.2.0 → 1.3.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/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +29 -1
- data/lib/marketingcloudsdk/client.rb +69 -22
- data/lib/marketingcloudsdk/version.rb +1 -1
- data/spec/client_spec.rb +286 -88
- data/spec/public_or_web_integration_credentials.rb.template +12 -0
- metadata +13 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6d1e7835b46241d74415cfc71fcf04898d24c36b4d7e02ecc2c79c0b4b43851
|
4
|
+
data.tar.gz: 6e49a53e6a97bda143d6cae5fb335f50dc793ea0da967c4236f69874137e7f17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7f5558179e22d3acf72b562b6ea219f1ffea55946ccab4bd2108e2e471f35102131113c6e4e58ad69801281e24d02a5e174006193ba018d26a14df79c60ec2a
|
7
|
+
data.tar.gz: aef480e9c3218532d934d69b9204b71822e7d2ee6c4a2eece74211bf8442196caa241328b43229a6e241b6baabd7130ca7104ace67d9fdd14632f7367deeeca1
|
@@ -0,0 +1,39 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Describe the issue you found
|
4
|
+
title: "[BUG]"
|
5
|
+
labels: bug
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior.
|
15
|
+
|
16
|
+
**Expected behavior**
|
17
|
+
A clear and concise description of what you expected to happen.
|
18
|
+
|
19
|
+
**Screenshots**
|
20
|
+
If applicable, add screenshots to help explain your problem.
|
21
|
+
|
22
|
+
**Code snippet**
|
23
|
+
A code snippet that demonstrates the issue or a link to a code repository the developers can easily pull down to recreate the issue locally.
|
24
|
+
|
25
|
+
Note: Because the developers need to copy and paste the code snippet, including a code snippet as a media file (e.g. gif) is not sufficient.
|
26
|
+
|
27
|
+
|
28
|
+
**Environment**
|
29
|
+
- SDK Version [e.g. 1.2.0]
|
30
|
+
- Ruby version
|
31
|
+
|
32
|
+
**The bug has the severity**
|
33
|
+
- [ ] Critical: The defect affects critical functionality or critical data. It does not have a workaround.
|
34
|
+
- [ ] Major: The defect affects major functionality or major data. It has a workaround but is not obvious and is difficult.
|
35
|
+
- [ ] Minor: The defect affects minor functionality or non-critical data. It has an easy workaround.
|
36
|
+
- [ ] Trivial: The defect does not affect functionality or data. It does not even need a workaround. It does not impact productivity or efficiency. It is merely an inconvenience.
|
37
|
+
|
38
|
+
**Additional context**
|
39
|
+
Add any other context about the problem here.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
title: "[Enhancement]"
|
5
|
+
labels: enhancement
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Is your feature request related to a problem? Please describe**
|
11
|
+
A clear and concise description of what the problem is.
|
12
|
+
|
13
|
+
**Describe the solution you'd like**
|
14
|
+
A clear and concise description of what you want to happen.
|
15
|
+
|
16
|
+
**Describe alternatives you've considered**
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
18
|
+
|
19
|
+
**Additional context**
|
20
|
+
Add any other context or screenshots about the feature request here.
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,6 +6,34 @@ ExactTarget Fuel SDK / SalesforceMarektingCloudSDK for Ruby
|
|
6
6
|
## Overview ##
|
7
7
|
The Fuel SDK for Ruby provides easy access to ExactTarget's Fuel API Family services, including a collection of REST APIs and a SOAP API. These APIs provide access to ExactTarget functionality via common collection types such as array/hash.
|
8
8
|
|
9
|
+
## New Features in Version 1.3.0 ##
|
10
|
+
- **Added Refresh Token support for OAuth2 authentication**
|
11
|
+
- **Added Web/Public App support for OAuth2 authentication**
|
12
|
+
|
13
|
+
More details on Access Tokens for Web/Public Apps can be found [here](https://developer.salesforce.com/docs/atlas.en-us.mc-app-development.meta/mc-app-development/access-token-app.htm)
|
14
|
+
|
15
|
+
Example of instantiating the Client class:
|
16
|
+
|
17
|
+
```
|
18
|
+
myclient = MarketingCloudSDK::Client.new({
|
19
|
+
'client' => {
|
20
|
+
'id' => '<CLIENT_ID>',
|
21
|
+
'secret' => '<CLIENT_SECRET>',
|
22
|
+
'request_token_url' => '<AUTH TENANT SPECIFIC ENDPOINT>',
|
23
|
+
'soap_endpoint' => '<SOAP TENANT SPECIFIC ENDPOINT>',
|
24
|
+
'base_api_url' => '<REST TENANT SPECIFIC ENDPOINT>',
|
25
|
+
'use_oAuth2_authentication' => true,
|
26
|
+
'account_id' => <TARGET_ACCOUNT_ID>,
|
27
|
+
'scope' => '<PERMISSION_LIST>',
|
28
|
+
'application_type' => '<APPLICATION_TYPE>',
|
29
|
+
'redirect_URI' => '<REDIRECT_URI_FOR_PUBLIC/WEB_APP>',
|
30
|
+
'authorization_code' => '<AUTHORIZATION_CODE_FOR_PUBLIC/WEB_APP>'
|
31
|
+
}
|
32
|
+
})
|
33
|
+
```
|
34
|
+
|
35
|
+
* application_type can have one of the following values: `server`, `public`, `web`. The default value of application_type is `server`.
|
36
|
+
|
9
37
|
|
10
38
|
## New Features in Version 1.2.0 ##
|
11
39
|
- **OAuth2 authentication support** - [More Details](https://developer.salesforce.com/docs/atlas.en-us.mc-app-development.meta/mc-app-development/integration-considerations.htm)
|
@@ -65,7 +93,7 @@ gem build marketingcloudsdk.gemspec
|
|
65
93
|
Install the newly built gem
|
66
94
|
|
67
95
|
```ruby
|
68
|
-
gem install marketingcloudsdk-1.
|
96
|
+
gem install marketingcloudsdk-1.3.0.gem
|
69
97
|
```
|
70
98
|
|
71
99
|
If you have not registered your application or you need to lookup your Application Key or Application Signature values, please go to App Center at [Code@: ExactTarget's Developer Community](http://code.exacttarget.com/appcenter "Code@ App Center").
|
@@ -78,7 +78,7 @@ module MarketingCloudSDK
|
|
78
78
|
class Client
|
79
79
|
attr_accessor :debug, :access_token, :auth_token, :internal_token, :refresh_token,
|
80
80
|
:id, :secret, :signature, :base_api_url, :package_name, :package_folders, :parent_folders, :auth_token_expiration,
|
81
|
-
:request_token_url, :soap_endpoint, :use_oAuth2_authentication, :account_id, :scope
|
81
|
+
:request_token_url, :soap_endpoint, :use_oAuth2_authentication, :account_id, :scope, :application_type, :authorization_code, :redirect_URI
|
82
82
|
|
83
83
|
include MarketingCloudSDK::Soap
|
84
84
|
include MarketingCloudSDK::Rest
|
@@ -86,12 +86,13 @@ module MarketingCloudSDK
|
|
86
86
|
def jwt= encoded_jwt
|
87
87
|
raise 'Require app signature to decode JWT' unless self.signature
|
88
88
|
decoded_jwt = JWT.decode(encoded_jwt, self.signature, true)
|
89
|
+
decoded_jwt_first = decoded_jwt.first
|
89
90
|
|
90
|
-
self.auth_token =
|
91
|
-
self.internal_token =
|
92
|
-
self.refresh_token =
|
93
|
-
self.auth_token_expiration = Time.new +
|
94
|
-
self.package_name =
|
91
|
+
self.auth_token = decoded_jwt_first['request']['user']['oauthToken']
|
92
|
+
self.internal_token = decoded_jwt_first['request']['user']['internalOauthToken']
|
93
|
+
self.refresh_token = decoded_jwt_first['request']['user']['refreshToken']
|
94
|
+
self.auth_token_expiration = Time.new + decoded_jwt_first['request']['user']['expiresIn']
|
95
|
+
self.package_name = decoded_jwt_first['request']['application']['package']
|
95
96
|
end
|
96
97
|
|
97
98
|
def initialize(params={}, debug=false)
|
@@ -108,6 +109,9 @@ module MarketingCloudSDK
|
|
108
109
|
self.use_oAuth2_authentication = client_config["use_oAuth2_authentication"]
|
109
110
|
self.account_id = client_config["account_id"]
|
110
111
|
self.scope = client_config["scope"]
|
112
|
+
self.application_type = client_config["application_type"]
|
113
|
+
self.authorization_code = client_config["authorization_code"]
|
114
|
+
self.redirect_URI = client_config["redirect_URI"]
|
111
115
|
end
|
112
116
|
|
113
117
|
# Set a default value in case no 'client' params is sent
|
@@ -123,6 +127,26 @@ module MarketingCloudSDK
|
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
130
|
+
if application_type.to_s.strip.empty?
|
131
|
+
self.application_type = 'server'
|
132
|
+
end
|
133
|
+
|
134
|
+
if ['web', 'public'].include? application_type
|
135
|
+
if authorization_code.to_s.strip.empty? or redirect_URI.to_s.strip.empty?
|
136
|
+
raise 'authorization_code or redirect_URI is null: For Public/Web Apps, the authorization_code and redirect_URI must be passed when instantiating Client'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if application_type == 'public'
|
141
|
+
if id.to_s.strip.empty?
|
142
|
+
raise 'id is null: id must be passed when instantiating Client'
|
143
|
+
end
|
144
|
+
else
|
145
|
+
if id.to_s.strip.empty? or secret.to_s.strip.empty?
|
146
|
+
raise 'id and secret must pe passed when instantiating Client'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
126
150
|
self.jwt = params['jwt'] if params['jwt']
|
127
151
|
self.refresh_token = params['refresh_token'] if params['refresh_token']
|
128
152
|
|
@@ -133,7 +157,6 @@ module MarketingCloudSDK
|
|
133
157
|
|
134
158
|
def refresh force=false
|
135
159
|
@refresh_mutex.synchronize do
|
136
|
-
raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
|
137
160
|
|
138
161
|
if (self.use_oAuth2_authentication == true)
|
139
162
|
self.refreshWithOAuth2(force)
|
@@ -169,43 +192,67 @@ module MarketingCloudSDK
|
|
169
192
|
end
|
170
193
|
|
171
194
|
def refreshWithOAuth2 force=false
|
172
|
-
raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
|
173
195
|
#If we don't already have a token or the token expires within 5 min(300 seconds)
|
174
196
|
if (self.access_token.nil? || Time.new + 300 > self.auth_token_expiration || force) then
|
175
|
-
payload = Hash.new.tap do |h|
|
176
|
-
h['client_id']= id
|
177
|
-
h['client_secret'] = secret
|
178
|
-
h['grant_type'] = 'client_credentials'
|
179
|
-
|
180
|
-
if (not self.account_id.to_s.strip.empty?)then
|
181
|
-
h['account_id'] = account_id
|
182
|
-
end
|
183
197
|
|
184
|
-
|
185
|
-
h['scope'] = scope
|
186
|
-
end
|
187
|
-
end
|
198
|
+
payload = createPayload
|
188
199
|
|
189
200
|
options = Hash.new.tap do |h|
|
190
201
|
h['data'] = payload
|
191
202
|
h['content_type'] = 'application/json'
|
192
203
|
end
|
193
204
|
|
194
|
-
|
205
|
+
auth_endpoint = request_token_url + '/v2/token'
|
195
206
|
|
196
|
-
response = post(
|
207
|
+
response = post(auth_endpoint, options)
|
197
208
|
raise "Unable to refresh token: #{response['message']}" unless response.has_key?('access_token')
|
198
209
|
|
199
210
|
self.access_token = response['access_token']
|
200
211
|
self.auth_token_expiration = Time.new + response['expires_in']
|
201
212
|
self.soap_endpoint = response['soap_instance_url'] + 'service.asmx'
|
202
213
|
self.base_api_url = response['rest_instance_url']
|
214
|
+
|
215
|
+
if response.has_key?('refresh_token')
|
216
|
+
self.refresh_token = response['refresh_token']
|
217
|
+
end
|
218
|
+
|
203
219
|
return true
|
204
220
|
else
|
205
221
|
return false
|
206
222
|
end
|
207
223
|
end
|
208
224
|
|
225
|
+
def createPayload
|
226
|
+
payload = Hash.new.tap do |h|
|
227
|
+
h['client_id'] = id
|
228
|
+
|
229
|
+
if application_type != 'public'
|
230
|
+
h['client_secret'] = secret
|
231
|
+
end
|
232
|
+
|
233
|
+
if !refresh_token.to_s.strip.empty?
|
234
|
+
h['grant_type'] = 'refresh_token'
|
235
|
+
h['refresh_token'] = refresh_token
|
236
|
+
elsif ['web', 'public'].include? application_type
|
237
|
+
h['grant_type'] = 'authorization_code'
|
238
|
+
h['code'] = authorization_code
|
239
|
+
h['redirect_uri'] = redirect_URI
|
240
|
+
else
|
241
|
+
h['grant_type'] = 'client_credentials'
|
242
|
+
end
|
243
|
+
|
244
|
+
unless account_id.to_s.strip.empty?
|
245
|
+
h['account_id'] = account_id
|
246
|
+
end
|
247
|
+
|
248
|
+
unless scope.to_s.strip.empty?
|
249
|
+
h['scope'] = scope
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
payload
|
254
|
+
end
|
255
|
+
|
209
256
|
def refresh!
|
210
257
|
refresh true
|
211
258
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,94 +1,208 @@
|
|
1
1
|
require 'spec_helper.rb'
|
2
|
+
require 'public_or_web_integration_credentials'
|
3
|
+
|
4
|
+
def get_test_stub
|
5
|
+
{'client' => {
|
6
|
+
'use_oAuth2_authentication' => true,
|
7
|
+
'id' => 'id',
|
8
|
+
'secret' => 'secret',
|
9
|
+
'request_token_url' => 'request_token_url',
|
10
|
+
'account_id' => 'account_id',
|
11
|
+
'authorization_code' => 'authorization_code',
|
12
|
+
'redirect_URI' => 'redirect_URI'
|
13
|
+
}}
|
14
|
+
end
|
2
15
|
|
3
|
-
describe
|
16
|
+
describe(MarketingCloudSDK::Client) do
|
4
17
|
|
5
18
|
context 'initialized' do
|
6
19
|
|
20
|
+
before(:each) do
|
21
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
22
|
+
end
|
23
|
+
|
7
24
|
it 'with client parameters' do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
expect(client.
|
13
|
-
expect(client.
|
14
|
-
expect(client.
|
25
|
+
test_stub = get_test_stub
|
26
|
+
|
27
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
28
|
+
|
29
|
+
expect(client.use_oAuth2_authentication).to be test_stub['client']['use_oAuth2_authentication']
|
30
|
+
expect(client.id).to eq test_stub['client']['id']
|
31
|
+
expect(client.secret).to eq test_stub['client']['secret']
|
32
|
+
expect(client.account_id).to eq test_stub['client']['account_id']
|
33
|
+
expect(client.request_token_url).to eq test_stub['client']['request_token_url']
|
15
34
|
end
|
16
35
|
|
17
36
|
it 'with debug=true' do
|
18
|
-
client = MarketingCloudSDK::Client.new(
|
37
|
+
client = MarketingCloudSDK::Client.new(get_test_stub, true)
|
38
|
+
|
19
39
|
expect(client.debug).to be true
|
20
40
|
end
|
21
41
|
|
22
42
|
it 'with debug=false' do
|
23
|
-
client = MarketingCloudSDK::Client.new(
|
43
|
+
client = MarketingCloudSDK::Client.new(get_test_stub, false)
|
44
|
+
|
24
45
|
expect(client.debug).to be false
|
25
46
|
end
|
26
47
|
|
27
|
-
it '
|
28
|
-
client = MarketingCloudSDK::Client.new(
|
29
|
-
expect(client.request_token_url).to eq 'fake/url'
|
30
|
-
end
|
48
|
+
it 'with base_api_url set to default value if base_api_url is not set' do
|
49
|
+
client = MarketingCloudSDK::Client.new(get_test_stub)
|
31
50
|
|
32
|
-
it 'sets the base_api_url url to a default if it does not exist' do
|
33
|
-
client = MarketingCloudSDK::Client.new({}, false)
|
34
51
|
expect(client.base_api_url).to eq 'https://www.exacttargetapis.com'
|
35
52
|
end
|
36
53
|
|
37
|
-
it '
|
38
|
-
|
39
|
-
|
54
|
+
it 'with null/blank/empty request_token_url and use_oAuth2_authentication=true should raise exception' do
|
55
|
+
expected_exception = 'request_token_url (Auth TSE) is mandatory when using OAuth2 authentication'
|
56
|
+
|
57
|
+
test_stub = get_test_stub
|
58
|
+
|
59
|
+
[nil, ' ', ''].each do |exception_raiser|
|
60
|
+
test_stub['client']['request_token_url'] = exception_raiser
|
61
|
+
expect { MarketingCloudSDK::Client.new(test_stub) }.to raise_error(expected_exception)
|
62
|
+
end
|
40
63
|
end
|
41
64
|
|
42
|
-
it '
|
43
|
-
client = MarketingCloudSDK::Client.new
|
65
|
+
it 'with SoapClient' do
|
66
|
+
client = MarketingCloudSDK::Client.new(get_test_stub)
|
67
|
+
|
44
68
|
expect(client).to be_kind_of MarketingCloudSDK::Soap
|
45
69
|
end
|
46
70
|
|
47
|
-
it '
|
48
|
-
client = MarketingCloudSDK::Client.new
|
71
|
+
it 'with RestClient' do
|
72
|
+
client = MarketingCloudSDK::Client.new(get_test_stub)
|
73
|
+
|
74
|
+
expect(client).to be_kind_of MarketingCloudSDK::Rest
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'with wsdl set to default value if not set in params' do
|
78
|
+
client = MarketingCloudSDK::Client.new(get_test_stub)
|
79
|
+
|
49
80
|
expect(client.wsdl).to eq 'https://webservice.exacttarget.com/etframework.wsdl'
|
50
81
|
end
|
51
82
|
|
52
|
-
it '
|
53
|
-
client = MarketingCloudSDK::Client.new
|
54
|
-
|
83
|
+
it 'with application_type set to \'server\' if application_type is not set in params' do
|
84
|
+
client = MarketingCloudSDK::Client.new(get_test_stub)
|
85
|
+
|
86
|
+
expect(client.application_type).to eq 'server'
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'with web/public app and null/blank/empty authorization_code or redirect_URI should raise exception' do
|
90
|
+
expected_exception = 'authorization_code or redirect_URI is null: For Public/Web Apps, the authorization_code and redirect_URI must be passed when instantiating Client'
|
91
|
+
|
92
|
+
exception_raisers = Hash.new.tap do |h|
|
93
|
+
h[nil] = 'nil'
|
94
|
+
h[' '] = 'blank string'
|
95
|
+
h[''] = 'empty string'
|
96
|
+
end
|
97
|
+
|
98
|
+
test_stub = get_test_stub
|
99
|
+
|
100
|
+
['web', 'public'].each do |app_type|
|
101
|
+
[nil, ' ', ''].each do |exception_raiser|
|
102
|
+
['authorization_code', 'redirect_URI'].each do |under_test_prop|
|
103
|
+
|
104
|
+
it "#{app_type} app with #{exception_raisers[exception_raiser]} #{under_test_prop} raises an exception" do
|
105
|
+
|
106
|
+
test_stub['client']['application_type'] = app_type
|
107
|
+
test_stub['client'][under_test_prop] = exception_raiser
|
108
|
+
|
109
|
+
expect { MarketingCloudSDK::Client.new(test_stub) }.to raise_error(expected_exception)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'with public app and null/blank/empty id should raise exception' do
|
117
|
+
expected_exception = 'id is null: id must be passed when instantiating Client'
|
118
|
+
|
119
|
+
test_stub = get_test_stub
|
120
|
+
test_stub['client']['application_type'] = 'public'
|
121
|
+
test_stub['client']['authorization_code'] = 'authorization_code'
|
122
|
+
test_stub['client']['redirect_URI'] = 'redirect_URI'
|
123
|
+
|
124
|
+
[nil, ' ', ''].each do |exception_raiser|
|
125
|
+
test_stub['client']['id'] = exception_raiser
|
126
|
+
|
127
|
+
expect { MarketingCloudSDK::Client.new(test_stub) }.to raise_error(expected_exception)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'with web/server app and null/blank/empty id or secret should raise exception' do
|
132
|
+
expected_exception = 'id and secret must pe passed when instantiating Client'
|
133
|
+
|
134
|
+
exception_raisers = Hash.new.tap do |h|
|
135
|
+
h[nil] = 'nil'
|
136
|
+
h[' '] = 'blank string'
|
137
|
+
h[''] = 'empty string'
|
138
|
+
end
|
139
|
+
|
140
|
+
test_stub = get_test_stub
|
141
|
+
test_stub['client']['authorization_code'] = 'authorization_code'
|
142
|
+
test_stub['client']['redirect_URI'] = 'redirect_URI'
|
143
|
+
|
144
|
+
['web', 'server'].each do |app_type|
|
145
|
+
[nil, ' ', ''].each do |exception_raiser|
|
146
|
+
['id', 'secret'].each do |under_test_prop|
|
147
|
+
|
148
|
+
it "#{app_type} app with #{exception_raisers[exception_raiser]} #{under_test_prop} raises an exception" do
|
149
|
+
|
150
|
+
test_stub['client']['application_type'] = app_type
|
151
|
+
test_stub['client'][under_test_prop] = exception_raiser
|
152
|
+
|
153
|
+
expect { MarketingCloudSDK::Client.new(test_stub) }.to raise_error(expected_exception)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
55
158
|
end
|
56
159
|
|
57
160
|
describe 'with a wsdl' do
|
58
161
|
|
59
|
-
|
162
|
+
test_stub = get_test_stub
|
163
|
+
|
164
|
+
let(:client) { MarketingCloudSDK::Client.new test_stub }
|
60
165
|
|
61
166
|
it'creates a SoapClient' do
|
62
167
|
expect(client).to be_kind_of MarketingCloudSDK::Soap
|
63
168
|
end
|
64
169
|
|
65
170
|
it'#wsdl returns default wsdl' do
|
66
|
-
expect(client.wsdl).to eq '
|
171
|
+
expect(client.wsdl).to eq 'https://webservice.exacttarget.com/etframework.wsdl'
|
67
172
|
end
|
68
173
|
end
|
69
174
|
end
|
70
175
|
|
71
176
|
context 'instance can set' do
|
72
177
|
|
73
|
-
|
178
|
+
before(:each) do
|
179
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:client) { MarketingCloudSDK::Client.new (get_test_stub)}
|
74
183
|
|
75
184
|
it 'client id' do
|
76
|
-
client.id =
|
77
|
-
|
185
|
+
client.id = 'some_id'
|
186
|
+
|
187
|
+
expect(client.id).to eq 'some_id'
|
78
188
|
end
|
79
189
|
|
80
190
|
it 'client secret' do
|
81
|
-
client.secret = '
|
82
|
-
|
191
|
+
client.secret = 'some_secret'
|
192
|
+
|
193
|
+
expect(client.secret).to eq 'some_secret'
|
83
194
|
end
|
84
195
|
|
85
196
|
it 'refresh token' do
|
86
|
-
client.refresh_token = '
|
87
|
-
|
197
|
+
client.refresh_token = 'some_refresh_token'
|
198
|
+
|
199
|
+
expect(client.refresh_token).to eq 'some_refresh_token'
|
88
200
|
end
|
89
201
|
|
90
202
|
it 'debug' do
|
203
|
+
client.debug = false
|
91
204
|
expect(client.debug).to be false
|
205
|
+
|
92
206
|
client.debug = true
|
93
207
|
expect(client.debug).to be true
|
94
208
|
end
|
@@ -97,23 +211,23 @@ describe MarketingCloudSDK::Client do
|
|
97
211
|
describe '#jwt=' do
|
98
212
|
|
99
213
|
let(:payload) {
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
214
|
+
{
|
215
|
+
'request' => {
|
216
|
+
'user'=> {
|
217
|
+
'oauthToken' => 'oAuthToken',
|
218
|
+
'expiresIn' => 3600,
|
219
|
+
'internalOauthToken' => 'internalOauthToken',
|
220
|
+
'refreshToken' => 'refreshToken'
|
221
|
+
},
|
222
|
+
'application'=> {
|
223
|
+
'package' => 'JustTesting'
|
224
|
+
}
|
225
|
+
}
|
111
226
|
}
|
112
|
-
}
|
113
227
|
}
|
114
228
|
|
115
229
|
let(:sig){
|
116
|
-
sig = '
|
230
|
+
sig = 'signature'
|
117
231
|
}
|
118
232
|
|
119
233
|
let(:encoded) {
|
@@ -121,13 +235,20 @@ describe MarketingCloudSDK::Client do
|
|
121
235
|
}
|
122
236
|
|
123
237
|
it 'raises an exception when signature is missing' do
|
124
|
-
|
238
|
+
test_stub = get_test_stub
|
239
|
+
test_stub['jwt'] = encoded
|
240
|
+
|
241
|
+
expect { MarketingCloudSDK::Client.new test_stub }.to raise_exception 'Require app signature to decode JWT'
|
125
242
|
end
|
126
243
|
|
127
244
|
describe 'decodes JWT' do
|
128
245
|
|
246
|
+
before(:each) do
|
247
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
248
|
+
end
|
249
|
+
|
129
250
|
let(:sig){
|
130
|
-
sig = '
|
251
|
+
sig = 'signature'
|
131
252
|
}
|
132
253
|
|
133
254
|
let(:encoded) {
|
@@ -135,84 +256,161 @@ describe MarketingCloudSDK::Client do
|
|
135
256
|
}
|
136
257
|
|
137
258
|
let(:client) {
|
138
|
-
|
259
|
+
test_stub = get_test_stub
|
260
|
+
test_stub['client']['signature'] = sig
|
261
|
+
test_stub['jwt'] = encoded
|
262
|
+
|
263
|
+
MarketingCloudSDK::Client.new test_stub
|
139
264
|
}
|
140
265
|
|
141
266
|
it 'making auth token available to client' do
|
142
|
-
client.
|
143
|
-
expect(client.auth_token).to eq 123456789
|
267
|
+
expect(client.auth_token).to eq payload['request']['user']['oauthToken']
|
144
268
|
end
|
145
269
|
|
146
270
|
it 'making internal token available to client' do
|
147
|
-
client.
|
148
|
-
expect(client.internal_token).to eq 987654321
|
271
|
+
expect(client.internal_token).to eq payload['request']['user']['internalOauthToken']
|
149
272
|
end
|
150
273
|
|
151
274
|
it 'making refresh token available to client' do
|
152
|
-
client.
|
153
|
-
expect(client.refresh_token).to eq 101010101010
|
275
|
+
expect(client.refresh_token).to eq payload['request']['user']['refreshToken']
|
154
276
|
end
|
155
277
|
end
|
156
278
|
end
|
157
279
|
|
158
280
|
describe '#refresh_token' do
|
159
|
-
|
281
|
+
|
282
|
+
before(:each) do
|
283
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
284
|
+
end
|
285
|
+
|
286
|
+
let(:client) { MarketingCloudSDK::Client.new get_test_stub }
|
160
287
|
|
161
288
|
it 'defaults to nil' do
|
162
289
|
expect(client.refresh_token).to be_nil
|
163
290
|
end
|
164
291
|
|
165
292
|
it 'can be accessed' do
|
166
|
-
client.refresh_token = '
|
167
|
-
expect(client.refresh_token).to eq '
|
293
|
+
client.refresh_token = 'refresh_token'
|
294
|
+
expect(client.refresh_token).to eq 'refresh_token'
|
168
295
|
end
|
169
296
|
end
|
170
297
|
|
171
|
-
|
298
|
+
context 'authentication payload' do
|
299
|
+
|
300
|
+
before(:each) do
|
301
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
302
|
+
end
|
172
303
|
|
173
|
-
|
304
|
+
it 'should have public app attributes' do
|
305
|
+
test_stub = get_test_stub
|
306
|
+
test_stub['client']['application_type'] = 'public'
|
174
307
|
|
175
|
-
|
308
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
176
309
|
|
177
|
-
|
178
|
-
expect { client.refresh }.to raise_exception 'Require Client Id and Client Secret to refresh tokens'
|
179
|
-
end
|
310
|
+
payload = client.createPayload
|
180
311
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
312
|
+
expect(client.id).to eq payload['client_id']
|
313
|
+
expect(client.redirect_URI).to eq payload['redirect_uri']
|
314
|
+
expect(client.authorization_code).to eq payload['code']
|
315
|
+
expect('authorization_code').to eq payload['grant_type']
|
316
|
+
end
|
185
317
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
318
|
+
it 'should not have client secret for public app' do
|
319
|
+
test_stub = get_test_stub
|
320
|
+
test_stub['client']['application_type'] = 'public'
|
321
|
+
|
322
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
323
|
+
|
324
|
+
payload = client.createPayload
|
325
|
+
|
326
|
+
expect(payload.key?('client_secret')).to be false
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'should have web app attributes' do
|
330
|
+
test_stub = get_test_stub
|
331
|
+
test_stub['client']['application_type'] = 'web'
|
332
|
+
|
333
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
334
|
+
|
335
|
+
payload = client.createPayload
|
336
|
+
|
337
|
+
expect('authorization_code').to eq payload['grant_type']
|
338
|
+
expect(client.id).to eq payload['client_id']
|
339
|
+
expect(client.secret).to eq payload['client_secret']
|
340
|
+
expect(client.redirect_URI).to eq payload['redirect_uri']
|
341
|
+
expect(client.authorization_code).to eq payload['code']
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'should have server attributes' do
|
345
|
+
test_stub = get_test_stub
|
346
|
+
test_stub['client']['application_type'] = 'server'
|
347
|
+
|
348
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
349
|
+
|
350
|
+
payload = client.createPayload
|
351
|
+
|
352
|
+
expect('client_credentials').to eq payload['grant_type']
|
353
|
+
expect(client.id).to eq payload['client_id']
|
354
|
+
expect(client.secret).to eq payload['client_secret']
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'should not have code and redirect_uri for server app' do
|
358
|
+
test_stub = get_test_stub
|
359
|
+
test_stub['client']['application_type'] = 'server'
|
360
|
+
|
361
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
362
|
+
|
363
|
+
payload = client.createPayload
|
364
|
+
|
365
|
+
expect(payload.key?('code')).to be false
|
366
|
+
expect(payload.key?('redirect_uri')).to be false
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'should have refresh_token attribute when refresh_token is not null/blank/empty on client' do
|
370
|
+
test_stub = get_test_stub
|
371
|
+
test_stub['refresh_token'] = 'refresh_token'
|
372
|
+
test_stub['client']['application_type'] = 'public'
|
373
|
+
|
374
|
+
client = MarketingCloudSDK::Client.new(test_stub)
|
375
|
+
|
376
|
+
payload = client.createPayload
|
377
|
+
|
378
|
+
expect('refresh_token').to eq payload['grant_type']
|
379
|
+
expect(client.refresh_token).to eq payload['refresh_token']
|
190
380
|
end
|
381
|
+
end
|
382
|
+
|
383
|
+
context 'for public and web integrations, access_token and refresh_token' do
|
384
|
+
# Test expects a Public/Web App integration config in spec/public_or_web_integration_credentials.rb
|
385
|
+
it 'should differ if refresh token is enforced' do
|
191
386
|
|
192
|
-
|
193
|
-
# let(:client) { MarketingCloudSDK::Client.new 'client' => { 'id' => 123, 'secret' => 'sssh'} }
|
194
|
-
# it 'accessType=offline' do
|
195
|
-
# client.stub(:post)
|
196
|
-
# .with({'clientId' => 123, 'secret' => 'ssh', 'accessType' => 'offline'})
|
197
|
-
# .and_return()
|
198
|
-
#end
|
387
|
+
client = MarketingCloudSDK::Client.new(auth)
|
199
388
|
|
200
|
-
|
201
|
-
|
389
|
+
auth_token1 = client.access_token
|
390
|
+
refresh_token1 = client.refresh_token
|
202
391
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
392
|
+
client.refreshWithOAuth2(true)
|
393
|
+
|
394
|
+
auth_token2 = client.access_token
|
395
|
+
refresh_token2 = client.refresh_token
|
396
|
+
|
397
|
+
expect(auth_token1).not_to eq(auth_token2)
|
398
|
+
expect(refresh_token1).not_to eq(refresh_token2)
|
399
|
+
end
|
207
400
|
end
|
208
401
|
|
209
402
|
describe 'includes HTTPRequest' do
|
210
403
|
|
211
|
-
|
404
|
+
before(:each) do
|
405
|
+
allow_any_instance_of(MarketingCloudSDK::Client).to receive(:refresh).and_return(true)
|
406
|
+
end
|
407
|
+
|
408
|
+
subject { MarketingCloudSDK::Client.new get_test_stub}
|
212
409
|
|
213
410
|
it { should respond_to(:get) }
|
214
411
|
it { should respond_to(:post) }
|
215
412
|
it { should respond_to(:patch) }
|
216
413
|
it { should respond_to(:delete) }
|
414
|
+
|
217
415
|
end
|
218
416
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
def auth
|
2
|
+
{
|
3
|
+
'client' => {
|
4
|
+
'id' => '<CLIENT_ID>',
|
5
|
+
'request_token_url' => '<AUTH TENANT SPECIFIC ENDPOINT>',
|
6
|
+
'use_oAuth2_authentication' => true,
|
7
|
+
'application_type' => '<APPLICATION_TYPE>',
|
8
|
+
'redirect_URI' => '<REDIRECT_URI_FOR_PUBLIC/WEB_APP>',
|
9
|
+
'authorization_code' => '<AUTHORIZATION_CODE_FOR_PUBLIC/WEB_APP>'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sfmc-fuelsdk-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salesforce
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -118,22 +118,22 @@ dependencies:
|
|
118
118
|
name: jwt
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '1.0'
|
124
121
|
- - ">="
|
125
122
|
- !ruby/object:Gem::Version
|
126
123
|
version: 1.0.0
|
124
|
+
- - "~>"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '1.0'
|
127
127
|
type: :runtime
|
128
128
|
prerelease: false
|
129
129
|
version_requirements: !ruby/object:Gem::Requirement
|
130
130
|
requirements:
|
131
|
-
- - "~>"
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '1.0'
|
134
131
|
- - ">="
|
135
132
|
- !ruby/object:Gem::Version
|
136
133
|
version: 1.0.0
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '1.0'
|
137
137
|
description: API wrapper for SOAP and REST API with Salesforce Marketing Cloud (ExactTarget)
|
138
138
|
email:
|
139
139
|
- mcsdkadmin@salesforce.com
|
@@ -141,6 +141,8 @@ executables: []
|
|
141
141
|
extensions: []
|
142
142
|
extra_rdoc_files: []
|
143
143
|
files:
|
144
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
145
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
144
146
|
- ".gitignore"
|
145
147
|
- Gemfile
|
146
148
|
- Gemfile.lock
|
@@ -193,6 +195,7 @@ files:
|
|
193
195
|
- spec/http_request_spec.rb
|
194
196
|
- spec/objects_helper_spec.rb
|
195
197
|
- spec/objects_spec.rb
|
198
|
+
- spec/public_or_web_integration_credentials.rb.template
|
196
199
|
- spec/rest_spec.rb
|
197
200
|
- spec/soap_spec.rb
|
198
201
|
- spec/spec_helper.rb
|
@@ -217,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
220
|
version: '0'
|
218
221
|
requirements: []
|
219
222
|
rubyforge_project:
|
220
|
-
rubygems_version: 2.7.
|
223
|
+
rubygems_version: 2.7.8
|
221
224
|
signing_key:
|
222
225
|
specification_version: 4
|
223
226
|
summary: Fuel Client Library for Ruby
|
@@ -256,6 +259,7 @@ test_files:
|
|
256
259
|
- spec/http_request_spec.rb
|
257
260
|
- spec/objects_helper_spec.rb
|
258
261
|
- spec/objects_spec.rb
|
262
|
+
- spec/public_or_web_integration_credentials.rb.template
|
259
263
|
- spec/rest_spec.rb
|
260
264
|
- spec/soap_spec.rb
|
261
265
|
- spec/spec_helper.rb
|