sfmc-fuelsdk-ruby 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +28 -28
  3. data/Gemfile +3 -3
  4. data/Gemfile.lock +92 -90
  5. data/Guardfile +8 -8
  6. data/LICENSE.md +13 -13
  7. data/README.md +166 -143
  8. data/Rakefile +1 -1
  9. data/lib/marketingcloudsdk.rb +74 -74
  10. data/lib/marketingcloudsdk/client.rb +348 -296
  11. data/lib/marketingcloudsdk/http_request.rb +118 -118
  12. data/lib/marketingcloudsdk/objects.rb +757 -757
  13. data/lib/marketingcloudsdk/rest.rb +118 -118
  14. data/lib/marketingcloudsdk/soap.rb +296 -282
  15. data/lib/marketingcloudsdk/targeting.rb +99 -99
  16. data/lib/marketingcloudsdk/utils.rb +47 -47
  17. data/lib/marketingcloudsdk/version.rb +39 -39
  18. data/lib/new.rb +1240 -1240
  19. data/marketingcloudsdk.gemspec +30 -30
  20. data/samples/sample-AddSubscriberToList.rb +56 -56
  21. data/samples/sample-CreateAndStartDataExtensionImport.rb +29 -29
  22. data/samples/sample-CreateAndStartListImport.rb +27 -27
  23. data/samples/sample-CreateContentAreas.rb +48 -48
  24. data/samples/sample-CreateDataExtensions.rb +54 -54
  25. data/samples/sample-CreateProfileAttributes.rb +48 -48
  26. data/samples/sample-SendEmailToDataExtension.rb +23 -23
  27. data/samples/sample-SendEmailToList.rb +23 -23
  28. data/samples/sample-SendTriggeredSends.rb +30 -30
  29. data/samples/sample-bounceevent.rb +70 -70
  30. data/samples/sample-campaign.rb +211 -211
  31. data/samples/sample-clickevent.rb +71 -71
  32. data/samples/sample-contentarea.rb +122 -122
  33. data/samples/sample-dataextension.rb +209 -209
  34. data/samples/sample-directverb.rb +54 -54
  35. data/samples/sample-email.rb +122 -122
  36. data/samples/sample-email.senddefinition.rb +134 -134
  37. data/samples/sample-folder.rb +143 -143
  38. data/samples/sample-import.rb +103 -103
  39. data/samples/sample-list.rb +105 -105
  40. data/samples/sample-list.subscriber.rb +97 -97
  41. data/samples/sample-openevent.rb +70 -70
  42. data/samples/sample-profileattribute.rb +56 -56
  43. data/samples/sample-sentevent.rb +70 -70
  44. data/samples/sample-subscriber.rb +135 -135
  45. data/samples/sample-triggeredsend.rb +129 -129
  46. data/samples/sample-unsubevent.rb +72 -72
  47. data/samples/sample_helper.rb.template +10 -10
  48. data/spec/client_spec.rb +218 -218
  49. data/spec/default_values_fallback_spec.rb +30 -30
  50. data/spec/helper_funcs_spec.rb +11 -11
  51. data/spec/http_request_spec.rb +61 -61
  52. data/spec/objects_helper_spec.rb +32 -32
  53. data/spec/objects_spec.rb +484 -484
  54. data/spec/rest_spec.rb +48 -48
  55. data/spec/soap_spec.rb +140 -140
  56. data/spec/spec_helper.rb +14 -14
  57. data/spec/targeting_spec.rb +44 -44
  58. metadata +9 -9
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require "bundler/gem_tasks"
@@ -1,74 +1,74 @@
1
- =begin
2
- Copyright (c) 2013 ExactTarget, Inc.
3
-
4
- All rights reserved.
5
-
6
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7
-
8
- following conditions are met:
9
-
10
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
11
-
12
- following disclaimer.
13
-
14
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
15
-
16
- following disclaimer in the documentation and/or other materials provided with the distribution.
17
-
18
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
19
-
20
- products derived from this software without specific prior written permission.
21
-
22
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
-
24
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
-
26
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
-
28
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
-
30
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
-
32
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33
-
34
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
- =end
36
-
37
- require "marketingcloudsdk/version"
38
-
39
- require 'rubygems'
40
- require 'date'
41
- require 'jwt'
42
-
43
- module MarketingCloudSDK
44
- require 'marketingcloudsdk/utils'
45
- autoload :HTTPRequest, 'marketingcloudsdk/http_request'
46
- autoload :Targeting, 'marketingcloudsdk/targeting'
47
- autoload :Soap, 'marketingcloudsdk/soap'
48
- autoload :Rest, 'marketingcloudsdk/rest'
49
- require 'marketingcloudsdk/client'
50
- require 'marketingcloudsdk/objects'
51
- end
52
-
53
- # backwards compatability
54
- ET_Client = MarketingCloudSDK::Client
55
- ET_BounceEvent = MarketingCloudSDK::BounceEvent
56
- ET_ClickEvent = MarketingCloudSDK::ClickEvent
57
- ET_ContentArea = MarketingCloudSDK::ContentArea
58
- ET_DataExtension = MarketingCloudSDK::DataExtension
59
- ET_DataFolder = MarketingCloudSDK::DataFolder
60
- ET_Folder = MarketingCloudSDK::Folder
61
- ET_Email = MarketingCloudSDK::Email
62
- ET_List = MarketingCloudSDK::List
63
- ET_OpenEvent = MarketingCloudSDK::OpenEvent
64
- ET_SentEvent = MarketingCloudSDK::SentEvent
65
- ET_Subscriber = MarketingCloudSDK::Subscriber
66
- ET_UnsubEvent = MarketingCloudSDK::UnsubEvent
67
- ET_TriggeredSend = MarketingCloudSDK::TriggeredSend
68
- ET_Campaign = MarketingCloudSDK::Campaign
69
- ET_Get = MarketingCloudSDK::Get
70
- ET_Post = MarketingCloudSDK::Post
71
- ET_Delete = MarketingCloudSDK::Delete
72
- ET_Patch = MarketingCloudSDK::Patch
73
- ET_ProfileAttribute = MarketingCloudSDK::ProfileAttribute
74
- ET_Import = MarketingCloudSDK::Import
1
+ =begin
2
+ Copyright (c) 2013 ExactTarget, Inc.
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7
+
8
+ following conditions are met:
9
+
10
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
11
+
12
+ following disclaimer.
13
+
14
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
15
+
16
+ following disclaimer in the documentation and/or other materials provided with the distribution.
17
+
18
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
19
+
20
+ products derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
+
24
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+
26
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
+
28
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
+
32
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33
+
34
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ =end
36
+
37
+ require "marketingcloudsdk/version"
38
+
39
+ require 'rubygems'
40
+ require 'date'
41
+ require 'jwt'
42
+
43
+ module MarketingCloudSDK
44
+ require 'marketingcloudsdk/utils'
45
+ autoload :HTTPRequest, 'marketingcloudsdk/http_request'
46
+ autoload :Targeting, 'marketingcloudsdk/targeting'
47
+ autoload :Soap, 'marketingcloudsdk/soap'
48
+ autoload :Rest, 'marketingcloudsdk/rest'
49
+ require 'marketingcloudsdk/client'
50
+ require 'marketingcloudsdk/objects'
51
+ end
52
+
53
+ # backwards compatability
54
+ ET_Client = MarketingCloudSDK::Client
55
+ ET_BounceEvent = MarketingCloudSDK::BounceEvent
56
+ ET_ClickEvent = MarketingCloudSDK::ClickEvent
57
+ ET_ContentArea = MarketingCloudSDK::ContentArea
58
+ ET_DataExtension = MarketingCloudSDK::DataExtension
59
+ ET_DataFolder = MarketingCloudSDK::DataFolder
60
+ ET_Folder = MarketingCloudSDK::Folder
61
+ ET_Email = MarketingCloudSDK::Email
62
+ ET_List = MarketingCloudSDK::List
63
+ ET_OpenEvent = MarketingCloudSDK::OpenEvent
64
+ ET_SentEvent = MarketingCloudSDK::SentEvent
65
+ ET_Subscriber = MarketingCloudSDK::Subscriber
66
+ ET_UnsubEvent = MarketingCloudSDK::UnsubEvent
67
+ ET_TriggeredSend = MarketingCloudSDK::TriggeredSend
68
+ ET_Campaign = MarketingCloudSDK::Campaign
69
+ ET_Get = MarketingCloudSDK::Get
70
+ ET_Post = MarketingCloudSDK::Post
71
+ ET_Delete = MarketingCloudSDK::Delete
72
+ ET_Patch = MarketingCloudSDK::Patch
73
+ ET_ProfileAttribute = MarketingCloudSDK::ProfileAttribute
74
+ ET_Import = MarketingCloudSDK::Import
@@ -1,296 +1,348 @@
1
- =begin
2
- Copyright (c) 2013 ExactTarget, Inc.
3
-
4
- All rights reserved.
5
-
6
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7
-
8
- following conditions are met:
9
-
10
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
11
-
12
- following disclaimer.
13
-
14
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
15
-
16
- following disclaimer in the documentation and/or other materials provided with the distribution.
17
-
18
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
19
-
20
- products derived from this software without specific prior written permission.
21
-
22
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
-
24
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
-
26
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
-
28
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
-
30
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
-
32
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33
-
34
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
-
36
- =end
37
-
38
- require 'securerandom'
39
- module MarketingCloudSDK
40
- class Response
41
- # not doing accessor so user, can't update these values from response.
42
- # You will see in the code some of these
43
- # items are being updated via back doors and such.
44
- attr_reader :code, :message, :results, :request_id, :body, :raw
45
-
46
- # some defaults
47
- def success
48
- @success ||= false
49
- end
50
- alias :success? :success
51
- alias :status :success # backward compatibility
52
-
53
- def more
54
- @more ||= false
55
- end
56
- alias :more? :more
57
-
58
- def initialize raw, client
59
- @client = client # keep connection with client in case we request more
60
- @results = []
61
- @raw = raw
62
- unpack raw
63
- rescue => ex # all else fails return raw
64
- puts ex.message
65
- raw
66
- end
67
-
68
- def continue
69
- raise NotImplementedError
70
- end
71
-
72
- private
73
- def unpack raw
74
- raise NotImplementedError
75
- end
76
- end
77
-
78
- class Client
79
- attr_accessor :debug, :access_token, :auth_token, :internal_token, :refresh_token,
80
- :id, :secret, :signature, :base_api_url, :package_name, :package_folders, :parent_folders, :auth_token_expiration,
81
- :request_token_url, :soap_endpoint
82
-
83
- include MarketingCloudSDK::Soap
84
- include MarketingCloudSDK::Rest
85
-
86
- def jwt= encoded_jwt
87
- raise 'Require app signature to decode JWT' unless self.signature
88
- decoded_jwt = JWT.decode(encoded_jwt, self.signature, true)
89
-
90
- self.auth_token = decoded_jwt['request']['user']['oauthToken']
91
- self.internal_token = decoded_jwt['request']['user']['internalOauthToken']
92
- self.refresh_token = decoded_jwt['request']['user']['refreshToken']
93
- self.auth_token_expiration = Time.new + decoded_jwt['request']['user']['expiresIn']
94
- self.package_name = decoded_jwt['request']['application']['package']
95
- end
96
-
97
- def initialize(params={}, debug=false)
98
- @refresh_mutex = Mutex.new
99
- self.debug = debug
100
- client_config = params['client']
101
- if client_config
102
- self.id = client_config["id"]
103
- self.secret = client_config["secret"]
104
- self.signature = client_config["signature"]
105
- self.base_api_url = !(client_config["base_api_url"].to_s.strip.empty?) ? client_config["base_api_url"] : 'https://www.exacttargetapis.com'
106
- self.request_token_url = !(client_config["request_token_url"].to_s.strip.empty?) ? client_config["request_token_url"] : 'https://auth.exacttargetapis.com/v1/requestToken'
107
- self.soap_endpoint = client_config["soap_endpoint"]
108
- end
109
-
110
- # Set a default value in case no 'client' params is sent
111
- if (!self.base_api_url)
112
- self.base_api_url = 'https://www.exacttargetapis.com'
113
- end
114
-
115
- # Leaving this for backwards compatibility
116
- if (!self.request_token_url)
117
- self.request_token_url = params['request_token_url'] ? params['request_token_url'] : 'https://auth.exacttargetapis.com/v1/requestToken'
118
- end
119
-
120
- self.jwt = params['jwt'] if params['jwt']
121
- self.refresh_token = params['refresh_token'] if params['refresh_token']
122
-
123
- self.wsdl = params["defaultwsdl"] if params["defaultwsdl"]
124
- end
125
-
126
- def refresh force=false
127
- @refresh_mutex.synchronize do
128
- raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
129
- #If we don't already have a token or the token expires within 5 min(300 seconds)
130
- if (self.access_token.nil? || Time.new + 300 > self.auth_token_expiration || force) then
131
- payload = Hash.new.tap do |h|
132
- h['clientId']= id
133
- h['clientSecret'] = secret
134
- h['refreshToken'] = refresh_token if refresh_token
135
- h['accessType'] = 'offline'
136
- end
137
-
138
- options = Hash.new.tap do |h|
139
- h['data'] = payload
140
- h['content_type'] = 'application/json'
141
- h['params'] = {'legacy' => 1}
142
- end
143
- response = post(request_token_url, options)
144
- raise "Unable to refresh token: #{response['message']}" unless response.has_key?('accessToken')
145
-
146
- self.access_token = response['accessToken']
147
- self.internal_token = response['legacyToken']
148
- self.auth_token_expiration = Time.new + response['expiresIn']
149
- self.refresh_token = response['refreshToken'] if response.has_key?("refreshToken")
150
- return true
151
- else
152
- return false
153
- end
154
- end
155
- end
156
-
157
- def refresh!
158
- refresh true
159
- end
160
-
161
- def AddSubscriberToList(email, ids, subscriber_key = nil)
162
- s = MarketingCloudSDK::Subscriber.new
163
- s.client = self
164
- lists = ids.collect{|id| {'ID' => id}}
165
- s.properties = {"EmailAddress" => email, "Lists" => lists}
166
- p s.properties
167
- s.properties['SubscriberKey'] = subscriber_key if subscriber_key
168
-
169
- # Try to add the subscriber
170
- if(rsp = s.post and rsp.results.first[:error_code] == '12014')
171
- # subscriber already exists we need to update.
172
- rsp = s.patch
173
- end
174
- rsp
175
- end
176
-
177
- def CreateDataExtensions(definitions)
178
- de = MarketingCloudSDK::DataExtension.new
179
- de.client = self
180
- de.properties = definitions
181
- de.post
182
- end
183
- def SendTriggeredSends(arrayOfTriggeredRecords)
184
- sendTS = ET_TriggeredSend.new
185
- sendTS.authStub = self
186
-
187
- sendTS.properties = arrayOfTriggeredRecords
188
- sendResponse = sendTS.send
189
-
190
- return sendResponse
191
- end
192
- def SendEmailToList(emailID, listID, sendClassificationCustomerKey)
193
- email = ET_Email::SendDefinition.new
194
- email.properties = {"Name"=>SecureRandom.uuid, "CustomerKey"=>SecureRandom.uuid, "Description"=>"Created with RubySDK"}
195
- email.properties["SendClassification"] = {"CustomerKey"=>sendClassificationCustomerKey}
196
- email.properties["SendDefinitionList"] = {"List"=> {"ID"=>listID}, "DataSourceTypeID"=>"List"}
197
- email.properties["Email"] = {"ID"=>emailID}
198
- email.authStub = self
199
- result = email.post
200
- if result.status then
201
- sendresult = email.send
202
- if sendresult.status then
203
- deleteresult = email.delete
204
- return sendresult
205
- else
206
- raise "Unable to send using send definition due to: #{result.results[0][:status_message]}"
207
- end
208
- else
209
- raise "Unable to create send definition due to: #{result.results[0][:status_message]}"
210
- end
211
- end
212
-
213
- def SendEmailToDataExtension(emailID, sendableDataExtensionCustomerKey, sendClassificationCustomerKey)
214
- email = ET_Email::SendDefinition.new
215
- email.properties = {"Name"=>SecureRandom.uuid, "CustomerKey"=>SecureRandom.uuid, "Description"=>"Created with RubySDK"}
216
- email.properties["SendClassification"] = {"CustomerKey"=> sendClassificationCustomerKey}
217
- email.properties["SendDefinitionList"] = {"CustomerKey"=> sendableDataExtensionCustomerKey, "DataSourceTypeID"=>"CustomObject"}
218
- email.properties["Email"] = {"ID"=>emailID}
219
- email.authStub = self
220
- result = email.post
221
- if result.status then
222
- sendresult = email.send
223
- if sendresult.status then
224
- deleteresult = email.delete
225
- return sendresult
226
- else
227
- raise "Unable to send using send definition due to: #{result.results[0][:status_message]}"
228
- end
229
- else
230
- raise "Unable to create send definition due to: #{result.results[0][:status_message]}"
231
- end
232
- end
233
- def CreateAndStartListImport(listId,fileName)
234
- import = ET_Import.new
235
- import.authStub = self
236
- import.properties = {"Name"=> "SDK Generated Import #{DateTime.now.to_s}"}
237
- import.properties["CustomerKey"] = SecureRandom.uuid
238
- import.properties["Description"] = "SDK Generated Import"
239
- import.properties["AllowErrors"] = "true"
240
- import.properties["DestinationObject"] = {"ID"=>listId}
241
- import.properties["FieldMappingType"] = "InferFromColumnHeadings"
242
- import.properties["FileSpec"] = fileName
243
- import.properties["FileType"] = "CSV"
244
- import.properties["RetrieveFileTransferLocation"] = {"CustomerKey"=>"ExactTarget Enhanced FTP"}
245
- import.properties["UpdateType"] = "AddAndUpdate"
246
- result = import.post
247
-
248
- if result.status then
249
- return import.start
250
- else
251
- raise "Unable to create import definition due to: #{result.results[0][:status_message]}"
252
- end
253
- end
254
-
255
- def CreateAndStartDataExtensionImport(dataExtensionCustomerKey, fileName, overwrite)
256
- import = ET_Import.new
257
- import.authStub = self
258
- import.properties = {"Name"=> "SDK Generated Import #{DateTime.now.to_s}"}
259
- import.properties["CustomerKey"] = SecureRandom.uuid
260
- import.properties["Description"] = "SDK Generated Import"
261
- import.properties["AllowErrors"] = "true"
262
- import.properties["DestinationObject"] = {"CustomerKey"=>dataExtensionCustomerKey}
263
- import.properties["FieldMappingType"] = "InferFromColumnHeadings"
264
- import.properties["FileSpec"] = fileName
265
- import.properties["FileType"] = "CSV"
266
- import.properties["RetrieveFileTransferLocation"] = {"CustomerKey"=>"ExactTarget Enhanced FTP"}
267
- if overwrite then
268
- import.properties["UpdateType"] = "Overwrite"
269
- else
270
- import.properties["UpdateType"] = "AddAndUpdate"
271
- end
272
- result = import.post
273
-
274
- if result.status then
275
- return import.start
276
- else
277
- raise "Unable to create import definition due to: #{result.results[0][:status_message]}"
278
- end
279
- end
280
-
281
- def CreateProfileAttributes(allAttributes)
282
- attrs = ET_ProfileAttribute.new
283
- attrs.authStub = self
284
- attrs.properties = allAttributes
285
- return attrs.post
286
- end
287
-
288
- def CreateContentAreas(arrayOfContentAreas)
289
- postC = ET_ContentArea.new
290
- postC.authStub = self
291
- postC.properties = arrayOfContentAreas
292
- sendResponse = postC.post
293
- return sendResponse
294
- end
295
- end
296
- end
1
+ =begin
2
+ Copyright (c) 2013 ExactTarget, Inc.
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7
+
8
+ following conditions are met:
9
+
10
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
11
+
12
+ following disclaimer.
13
+
14
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
15
+
16
+ following disclaimer in the documentation and/or other materials provided with the distribution.
17
+
18
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
19
+
20
+ products derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
+
24
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+
26
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
+
28
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
+
32
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33
+
34
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ =end
37
+
38
+ require 'securerandom'
39
+ module MarketingCloudSDK
40
+ class Response
41
+ # not doing accessor so user, can't update these values from response.
42
+ # You will see in the code some of these
43
+ # items are being updated via back doors and such.
44
+ attr_reader :code, :message, :results, :request_id, :body, :raw
45
+
46
+ # some defaults
47
+ def success
48
+ @success ||= false
49
+ end
50
+ alias :success? :success
51
+ alias :status :success # backward compatibility
52
+
53
+ def more
54
+ @more ||= false
55
+ end
56
+ alias :more? :more
57
+
58
+ def initialize raw, client
59
+ @client = client # keep connection with client in case we request more
60
+ @results = []
61
+ @raw = raw
62
+ unpack raw
63
+ rescue => ex # all else fails return raw
64
+ puts ex.message
65
+ raw
66
+ end
67
+
68
+ def continue
69
+ raise NotImplementedError
70
+ end
71
+
72
+ private
73
+ def unpack raw
74
+ raise NotImplementedError
75
+ end
76
+ end
77
+
78
+ class Client
79
+ attr_accessor :debug, :access_token, :auth_token, :internal_token, :refresh_token,
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
82
+
83
+ include MarketingCloudSDK::Soap
84
+ include MarketingCloudSDK::Rest
85
+
86
+ def jwt= encoded_jwt
87
+ raise 'Require app signature to decode JWT' unless self.signature
88
+ decoded_jwt = JWT.decode(encoded_jwt, self.signature, true)
89
+
90
+ self.auth_token = decoded_jwt['request']['user']['oauthToken']
91
+ self.internal_token = decoded_jwt['request']['user']['internalOauthToken']
92
+ self.refresh_token = decoded_jwt['request']['user']['refreshToken']
93
+ self.auth_token_expiration = Time.new + decoded_jwt['request']['user']['expiresIn']
94
+ self.package_name = decoded_jwt['request']['application']['package']
95
+ end
96
+
97
+ def initialize(params={}, debug=false)
98
+ @refresh_mutex = Mutex.new
99
+ self.debug = debug
100
+ client_config = params['client']
101
+ if client_config
102
+ self.id = client_config["id"]
103
+ self.secret = client_config["secret"]
104
+ self.signature = client_config["signature"]
105
+ self.base_api_url = !(client_config["base_api_url"].to_s.strip.empty?) ? client_config["base_api_url"] : 'https://www.exacttargetapis.com'
106
+ self.request_token_url = client_config["request_token_url"]
107
+ self.soap_endpoint = client_config["soap_endpoint"]
108
+ self.use_oAuth2_authentication = client_config["use_oAuth2_authentication"]
109
+ self.account_id = client_config["account_id"]
110
+ self.scope = client_config["scope"]
111
+ end
112
+
113
+ # Set a default value in case no 'client' params is sent
114
+ if (!self.base_api_url)
115
+ self.base_api_url = 'https://www.exacttargetapis.com'
116
+ end
117
+
118
+ if (self.request_token_url.to_s.strip.empty?)
119
+ if(use_oAuth2_authentication == true)
120
+ raise 'request_token_url (Auth TSE) is mandatory when using OAuth2 authentication'
121
+ else
122
+ self.request_token_url = 'https://auth.exacttargetapis.com/v1/requestToken'
123
+ end
124
+ end
125
+
126
+ self.jwt = params['jwt'] if params['jwt']
127
+ self.refresh_token = params['refresh_token'] if params['refresh_token']
128
+
129
+ self.wsdl = params["defaultwsdl"] if params["defaultwsdl"]
130
+
131
+ self.refresh
132
+ end
133
+
134
+ def refresh force=false
135
+ @refresh_mutex.synchronize do
136
+ raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
137
+
138
+ if (self.use_oAuth2_authentication == true)
139
+ self.refreshWithOAuth2(force)
140
+ return
141
+ end
142
+
143
+ #If we don't already have a token or the token expires within 5 min(300 seconds)
144
+ if (self.access_token.nil? || Time.new + 300 > self.auth_token_expiration || force) then
145
+ payload = Hash.new.tap do |h|
146
+ h['clientId']= id
147
+ h['clientSecret'] = secret
148
+ h['refreshToken'] = refresh_token if refresh_token
149
+ h['accessType'] = 'offline'
150
+ end
151
+
152
+ options = Hash.new.tap do |h|
153
+ h['data'] = payload
154
+ h['content_type'] = 'application/json'
155
+ h['params'] = {'legacy' => 1}
156
+ end
157
+ response = post(request_token_url, options)
158
+ raise "Unable to refresh token: #{response['message']}" unless response.has_key?('accessToken')
159
+
160
+ self.access_token = response['accessToken']
161
+ self.internal_token = response['legacyToken']
162
+ self.auth_token_expiration = Time.new + response['expiresIn']
163
+ self.refresh_token = response['refreshToken'] if response.has_key?("refreshToken")
164
+ return true
165
+ else
166
+ return false
167
+ end
168
+ end
169
+ end
170
+
171
+ def refreshWithOAuth2 force=false
172
+ raise 'Require Client Id and Client Secret to refresh tokens' unless (id && secret)
173
+ #If we don't already have a token or the token expires within 5 min(300 seconds)
174
+ 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
+
184
+ if (not self.scope.to_s.strip.empty?)then
185
+ h['scope'] = scope
186
+ end
187
+ end
188
+
189
+ options = Hash.new.tap do |h|
190
+ h['data'] = payload
191
+ h['content_type'] = 'application/json'
192
+ end
193
+
194
+ self.request_token_url += '/v2/token'
195
+
196
+ response = post(request_token_url, options)
197
+ raise "Unable to refresh token: #{response['message']}" unless response.has_key?('access_token')
198
+
199
+ self.access_token = response['access_token']
200
+ self.auth_token_expiration = Time.new + response['expires_in']
201
+ self.soap_endpoint = response['soap_instance_url'] + 'service.asmx'
202
+ self.base_api_url = response['rest_instance_url']
203
+ return true
204
+ else
205
+ return false
206
+ end
207
+ end
208
+
209
+ def refresh!
210
+ refresh true
211
+ end
212
+
213
+ def AddSubscriberToList(email, ids, subscriber_key = nil)
214
+ s = MarketingCloudSDK::Subscriber.new
215
+ s.client = self
216
+ lists = ids.collect{|id| {'ID' => id}}
217
+ s.properties = {"EmailAddress" => email, "Lists" => lists}
218
+ p s.properties
219
+ s.properties['SubscriberKey'] = subscriber_key if subscriber_key
220
+
221
+ # Try to add the subscriber
222
+ if(rsp = s.post and rsp.results.first[:error_code] == '12014')
223
+ # subscriber already exists we need to update.
224
+ rsp = s.patch
225
+ end
226
+ rsp
227
+ end
228
+
229
+ def CreateDataExtensions(definitions)
230
+ de = MarketingCloudSDK::DataExtension.new
231
+ de.client = self
232
+ de.properties = definitions
233
+ de.post
234
+ end
235
+ def SendTriggeredSends(arrayOfTriggeredRecords)
236
+ sendTS = ET_TriggeredSend.new
237
+ sendTS.authStub = self
238
+
239
+ sendTS.properties = arrayOfTriggeredRecords
240
+ sendResponse = sendTS.send
241
+
242
+ return sendResponse
243
+ end
244
+ def SendEmailToList(emailID, listID, sendClassificationCustomerKey)
245
+ email = ET_Email::SendDefinition.new
246
+ email.properties = {"Name"=>SecureRandom.uuid, "CustomerKey"=>SecureRandom.uuid, "Description"=>"Created with RubySDK"}
247
+ email.properties["SendClassification"] = {"CustomerKey"=>sendClassificationCustomerKey}
248
+ email.properties["SendDefinitionList"] = {"List"=> {"ID"=>listID}, "DataSourceTypeID"=>"List"}
249
+ email.properties["Email"] = {"ID"=>emailID}
250
+ email.authStub = self
251
+ result = email.post
252
+ if result.status then
253
+ sendresult = email.send
254
+ if sendresult.status then
255
+ deleteresult = email.delete
256
+ return sendresult
257
+ else
258
+ raise "Unable to send using send definition due to: #{result.results[0][:status_message]}"
259
+ end
260
+ else
261
+ raise "Unable to create send definition due to: #{result.results[0][:status_message]}"
262
+ end
263
+ end
264
+
265
+ def SendEmailToDataExtension(emailID, sendableDataExtensionCustomerKey, sendClassificationCustomerKey)
266
+ email = ET_Email::SendDefinition.new
267
+ email.properties = {"Name"=>SecureRandom.uuid, "CustomerKey"=>SecureRandom.uuid, "Description"=>"Created with RubySDK"}
268
+ email.properties["SendClassification"] = {"CustomerKey"=> sendClassificationCustomerKey}
269
+ email.properties["SendDefinitionList"] = {"CustomerKey"=> sendableDataExtensionCustomerKey, "DataSourceTypeID"=>"CustomObject"}
270
+ email.properties["Email"] = {"ID"=>emailID}
271
+ email.authStub = self
272
+ result = email.post
273
+ if result.status then
274
+ sendresult = email.send
275
+ if sendresult.status then
276
+ deleteresult = email.delete
277
+ return sendresult
278
+ else
279
+ raise "Unable to send using send definition due to: #{result.results[0][:status_message]}"
280
+ end
281
+ else
282
+ raise "Unable to create send definition due to: #{result.results[0][:status_message]}"
283
+ end
284
+ end
285
+ def CreateAndStartListImport(listId,fileName)
286
+ import = ET_Import.new
287
+ import.authStub = self
288
+ import.properties = {"Name"=> "SDK Generated Import #{DateTime.now.to_s}"}
289
+ import.properties["CustomerKey"] = SecureRandom.uuid
290
+ import.properties["Description"] = "SDK Generated Import"
291
+ import.properties["AllowErrors"] = "true"
292
+ import.properties["DestinationObject"] = {"ID"=>listId}
293
+ import.properties["FieldMappingType"] = "InferFromColumnHeadings"
294
+ import.properties["FileSpec"] = fileName
295
+ import.properties["FileType"] = "CSV"
296
+ import.properties["RetrieveFileTransferLocation"] = {"CustomerKey"=>"ExactTarget Enhanced FTP"}
297
+ import.properties["UpdateType"] = "AddAndUpdate"
298
+ result = import.post
299
+
300
+ if result.status then
301
+ return import.start
302
+ else
303
+ raise "Unable to create import definition due to: #{result.results[0][:status_message]}"
304
+ end
305
+ end
306
+
307
+ def CreateAndStartDataExtensionImport(dataExtensionCustomerKey, fileName, overwrite)
308
+ import = ET_Import.new
309
+ import.authStub = self
310
+ import.properties = {"Name"=> "SDK Generated Import #{DateTime.now.to_s}"}
311
+ import.properties["CustomerKey"] = SecureRandom.uuid
312
+ import.properties["Description"] = "SDK Generated Import"
313
+ import.properties["AllowErrors"] = "true"
314
+ import.properties["DestinationObject"] = {"CustomerKey"=>dataExtensionCustomerKey}
315
+ import.properties["FieldMappingType"] = "InferFromColumnHeadings"
316
+ import.properties["FileSpec"] = fileName
317
+ import.properties["FileType"] = "CSV"
318
+ import.properties["RetrieveFileTransferLocation"] = {"CustomerKey"=>"ExactTarget Enhanced FTP"}
319
+ if overwrite then
320
+ import.properties["UpdateType"] = "Overwrite"
321
+ else
322
+ import.properties["UpdateType"] = "AddAndUpdate"
323
+ end
324
+ result = import.post
325
+
326
+ if result.status then
327
+ return import.start
328
+ else
329
+ raise "Unable to create import definition due to: #{result.results[0][:status_message]}"
330
+ end
331
+ end
332
+
333
+ def CreateProfileAttributes(allAttributes)
334
+ attrs = ET_ProfileAttribute.new
335
+ attrs.authStub = self
336
+ attrs.properties = allAttributes
337
+ return attrs.post
338
+ end
339
+
340
+ def CreateContentAreas(arrayOfContentAreas)
341
+ postC = ET_ContentArea.new
342
+ postC.authStub = self
343
+ postC.properties = arrayOfContentAreas
344
+ sendResponse = postC.post
345
+ return sendResponse
346
+ end
347
+ end
348
+ end