fuelsdk_json_bump 0.0.5

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +26 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +91 -0
  5. data/Guardfile +8 -0
  6. data/LICENSE.md +13 -0
  7. data/README.md +127 -0
  8. data/Rakefile +1 -0
  9. data/fuelsdk.gemspec +30 -0
  10. data/lib/fuelsdk.rb +74 -0
  11. data/lib/fuelsdk/client.rb +282 -0
  12. data/lib/fuelsdk/http_request.rb +116 -0
  13. data/lib/fuelsdk/objects.rb +757 -0
  14. data/lib/fuelsdk/rest.rb +122 -0
  15. data/lib/fuelsdk/soap.rb +288 -0
  16. data/lib/fuelsdk/targeting.rb +58 -0
  17. data/lib/fuelsdk/utils.rb +47 -0
  18. data/lib/fuelsdk/version.rb +39 -0
  19. data/lib/new.rb +1240 -0
  20. data/samples/sample-AddSubscriberToList.rb +56 -0
  21. data/samples/sample-CreateAndStartDataExtensionImport.rb +29 -0
  22. data/samples/sample-CreateAndStartListImport.rb +27 -0
  23. data/samples/sample-CreateContentAreas.rb +48 -0
  24. data/samples/sample-CreateDataExtensions.rb +54 -0
  25. data/samples/sample-CreateProfileAttributes.rb +48 -0
  26. data/samples/sample-SendEmailToDataExtension.rb +23 -0
  27. data/samples/sample-SendEmailToList.rb +23 -0
  28. data/samples/sample-SendTriggeredSends.rb +30 -0
  29. data/samples/sample-bounceevent.rb +70 -0
  30. data/samples/sample-campaign.rb +211 -0
  31. data/samples/sample-clickevent.rb +71 -0
  32. data/samples/sample-contentarea.rb +122 -0
  33. data/samples/sample-dataextension.rb +209 -0
  34. data/samples/sample-directverb.rb +55 -0
  35. data/samples/sample-email.rb +122 -0
  36. data/samples/sample-email.senddefinition.rb +134 -0
  37. data/samples/sample-folder.rb +143 -0
  38. data/samples/sample-import.rb +104 -0
  39. data/samples/sample-list.rb +105 -0
  40. data/samples/sample-list.subscriber.rb +97 -0
  41. data/samples/sample-openevent.rb +70 -0
  42. data/samples/sample-profileattribute.rb +57 -0
  43. data/samples/sample-sentevent.rb +70 -0
  44. data/samples/sample-subscriber.rb +136 -0
  45. data/samples/sample-triggeredsend.rb +130 -0
  46. data/samples/sample-unsubevent.rb +72 -0
  47. data/samples/sample_helper.rb.template +8 -0
  48. data/spec/client_spec.rb +200 -0
  49. data/spec/helper_funcs_spec.rb +11 -0
  50. data/spec/http_request_spec.rb +36 -0
  51. data/spec/objects_helper_spec.rb +32 -0
  52. data/spec/objects_spec.rb +484 -0
  53. data/spec/rest_spec.rb +48 -0
  54. data/spec/soap_spec.rb +140 -0
  55. data/spec/spec_helper.rb +14 -0
  56. data/spec/targeting_spec.rb +39 -0
  57. metadata +250 -0
@@ -0,0 +1,122 @@
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
+ module FuelSDK
38
+ module Rest
39
+
40
+ include FuelSDK::Targeting
41
+
42
+ def rest_client
43
+ self
44
+ end
45
+
46
+ def normalize_keys obj
47
+ if obj and obj.is_a? Hash
48
+ obj.keys.each do |k|
49
+ obj[(k.to_sym rescue k) || k] = obj.delete(k)
50
+ end
51
+ end
52
+ obj
53
+ end
54
+
55
+ def get_url_properties url, properties
56
+ url_property_names = url.scan(/(%{(.+?)})/).collect{|frmt, name| name}
57
+ url_properties = {}
58
+ properties.keys.each do |k|
59
+ if url_property_names.include? k
60
+ url_properties[k] = properties.delete(k)
61
+ end
62
+ end
63
+ url_properties
64
+ end
65
+
66
+ def complete_url url, url_properties
67
+ normalize_keys(url_properties)
68
+ url = url % url_properties if url_properties
69
+ url.end_with?('/') ? url.chop : url
70
+ rescue KeyError => ex
71
+ raise "#{ex.message} to complete #{url}"
72
+ end
73
+
74
+ def parse_properties url, properties
75
+ url_properties = get_url_properties url, properties
76
+ url = complete_url url, url_properties
77
+ [url, properties]
78
+ end
79
+
80
+ def rest_get url, properties={}
81
+ url, properties = parse_properties url, properties
82
+ rest_request :get, url, {'params' => properties}
83
+ end
84
+
85
+ def rest_delete url, properties={}
86
+ url, properties = parse_properties url, properties
87
+ rest_request :delete, url
88
+ end
89
+
90
+ def rest_patch url, properties={}
91
+ url, payload = parse_properties url, properties
92
+ rest_request :patch, url, {'data' => payload,
93
+ 'content_type' => 'application/json'}
94
+ end
95
+
96
+ def rest_post url, properties={}
97
+ url, payload = parse_properties url, properties
98
+ rest_request :post, url, {'data' => payload,
99
+ 'content_type' => 'application/json'}
100
+ end
101
+
102
+ private
103
+ def rest_request action, url, options={}
104
+ retried = false
105
+ begin
106
+ #Try to refresh the token and if we do then we need to regenerate the header as well.
107
+ self.refresh
108
+ (options['params'] ||= {}).merge! 'access_token' => access_token
109
+ rsp = rest_client.send(action, url, options)
110
+ raise 'Unauthorized' if rsp.message == 'Unauthorized'
111
+ rescue
112
+ raise if retried
113
+ self.refresh! # ask for forgiveness not, permission
114
+ retried = true
115
+ retry
116
+ end
117
+ rsp
118
+ rescue
119
+ rsp
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,288 @@
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 'savon'
38
+ module FuelSDK
39
+
40
+ class SoapResponse < FuelSDK::Response
41
+
42
+ def continue
43
+ rsp = nil
44
+ if more?
45
+ rsp = unpack @client.soap_client.call(:retrieve, :message => {'ContinueRequest' => request_id})
46
+ else
47
+ puts 'No more data'
48
+ end
49
+
50
+ rsp
51
+ end
52
+
53
+ private
54
+ def unpack_body raw
55
+ @body = raw.body
56
+ @request_id = raw.body[raw.body.keys.first][:request_id]
57
+ unpack_msg raw
58
+ rescue
59
+ @message = raw.http.body
60
+ @body = raw.http.body unless @body
61
+ end
62
+
63
+ def unpack raw
64
+ @code = raw.http.code
65
+ unpack_body raw
66
+ @success = @message == 'OK'
67
+ @results += (unpack_rslts raw)
68
+ end
69
+
70
+ def unpack_msg raw
71
+ @message = raw.soap_fault? ? raw.body[:fault][:faultstring] : raw.body[raw.body.keys.first][:overall_status]
72
+ end
73
+
74
+ def unpack_rslts raw
75
+ @more = (raw.body[raw.body.keys.first][:overall_status] == 'MoreDataAvailable')
76
+ rslts = raw.body[raw.body.keys.first][:results] || []
77
+ rslts = [rslts] unless rslts.kind_of? Array
78
+ rslts
79
+ rescue
80
+ []
81
+ end
82
+ end
83
+
84
+ class DescribeResponse < SoapResponse
85
+ attr_reader :properties, :retrievable, :updatable, :required, :extended, :viewable, :editable
86
+ private
87
+
88
+ def unpack_rslts raw
89
+ @retrievable, @updatable, @required, @properties, @extended, @viewable, @editable = [], [], [], [], [], [], [], []
90
+ definition = raw.body[raw.body.keys.first][:object_definition]
91
+ _props = definition[:properties]
92
+ _props.each do |p|
93
+ @retrievable << p[:name] if p[:is_retrievable] and (p[:name] != 'DataRetentionPeriod')
94
+ @updatable << p[:name] if p[:is_updatable]
95
+ @required << p[:name] if p[:is_required]
96
+ @properties << p[:name]
97
+ end
98
+ # ugly, but a necessary evil
99
+ _exts = definition[:extended_properties].nil? ? {} : definition[:extended_properties] # if they have no extended properties nil is returned
100
+ _exts = _exts[:extended_property] || [] # if no properties nil and we need an array to iterate
101
+ _exts = [_exts] unless _exts.kind_of? Array # if they have only one extended property we need to wrap it in array to iterate
102
+ _exts.each do |p|
103
+ @viewable << p[:name] if p[:is_viewable]
104
+ @editable << p[:name] if p[:is_editable]
105
+ @extended << p[:name]
106
+ end
107
+ @success = true # overall_status is missing from definition response, so need to set here manually
108
+ _props + _exts
109
+ rescue
110
+ @message = "Unable to describe #{raw.locals[:message]['DescribeRequests']['ObjectDefinitionRequest']['ObjectType']}"
111
+ @success = false
112
+ []
113
+ end
114
+ end
115
+
116
+ module Soap
117
+ attr_accessor :wsdl, :debug#, :internal_token
118
+
119
+ include FuelSDK::Targeting
120
+
121
+ def header
122
+ raise 'Require legacy token for soap header' unless internal_token
123
+ {
124
+ 'oAuth' => {'oAuthToken' => internal_token},
125
+ :attributes! => { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }}
126
+ }
127
+ end
128
+
129
+ def debug
130
+ @debug ||= false
131
+ end
132
+
133
+ def wsdl
134
+ @wsdl ||= 'https://webservice.exacttarget.com/etframework.wsdl'
135
+ end
136
+
137
+ def soap_client
138
+ self.refresh
139
+ @soap_client = Savon.client(
140
+ soap_header: header,
141
+ wsdl: wsdl,
142
+ endpoint: endpoint,
143
+ wsse_auth: ["*", "*"],
144
+ raise_errors: false,
145
+ log: debug,
146
+ open_timeout:180,
147
+ read_timeout: 180
148
+ )
149
+ end
150
+
151
+ def soap_describe object_type
152
+ message = {
153
+ 'DescribeRequests' => {
154
+ 'ObjectDefinitionRequest' => {
155
+ 'ObjectType' => object_type
156
+ }
157
+ }
158
+ }
159
+ soap_request :describe, message
160
+ end
161
+
162
+ def soap_perform object_type, action, properties
163
+ message = {}
164
+ message['Action'] = action
165
+ message['Definitions'] = {'Definition' => properties}
166
+ message['Definitions'][:attributes!] = { 'Definition' => { 'xsi:type' => ('tns:' + object_type) }}
167
+
168
+ soap_request :perform, message
169
+ end
170
+
171
+
172
+ def soap_configure object_type, action, properties
173
+ message = {}
174
+ message['Action'] = action
175
+ message['Configurations'] = {}
176
+ if properties.is_a? Array then
177
+ message['Configurations']['Configuration'] = []
178
+ properties.each do |configItem|
179
+ message['Configurations']['Configuration'] << configItem
180
+ end
181
+ else
182
+ message['Configurations'] = {'Configuration' => properties}
183
+ end
184
+ message['Configurations'][:attributes!] = { 'Configuration' => { 'xsi:type' => ('tns:' + object_type) }}
185
+
186
+ soap_request :configure, message
187
+ end
188
+
189
+ def soap_get object_type, properties=nil, filter=nil
190
+ if properties.nil? or properties.empty?
191
+ rsp = soap_describe object_type
192
+ if rsp.success?
193
+ properties = rsp.retrievable
194
+ else
195
+ rsp.instance_variable_set(:@message, "Unable to get #{object_type}") # back door update
196
+ return rsp
197
+ end
198
+ elsif properties.kind_of? Hash
199
+ properties = properties.keys
200
+ elsif properties.kind_of? String
201
+ properties = [properties]
202
+ end
203
+
204
+ message = {'ObjectType' => object_type, 'Properties' => properties}
205
+
206
+ if filter and filter.kind_of? Hash
207
+ message['Filter'] = filter
208
+ message[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:SimpleFilterPart' } }
209
+
210
+ if filter.has_key?('LogicalOperator')
211
+ message[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:ComplexFilterPart' }}
212
+ message['Filter'][:attributes!] = {
213
+ 'LeftOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' },
214
+ 'RightOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' }}
215
+ end
216
+ end
217
+ message = {'RetrieveRequest' => message}
218
+
219
+ soap_request :retrieve, message
220
+ end
221
+
222
+ def soap_post object_type, properties
223
+ soap_cud :create, object_type, properties
224
+ end
225
+
226
+ def soap_patch object_type, properties
227
+ soap_cud :update, object_type, properties
228
+ end
229
+
230
+ def soap_delete object_type, properties
231
+ soap_cud :delete, object_type, properties
232
+ end
233
+
234
+ def soap_put object_type, properties
235
+ soap_cud :update, object_type, properties, true
236
+ end
237
+
238
+ private
239
+
240
+ def soap_cud action, object_type, properties, upsert=nil
241
+ # get a list of attributes so we can seperate
242
+ # them from standard object properties
243
+ #type_attrs = soap_describe(object_type).editable
244
+
245
+ #
246
+ # properties = [properties] unless properties.kind_of? Array
247
+ # properties.each do |p|
248
+ # formated_attrs = []
249
+ # p.each do |k, v|
250
+ # if type_attrs.include? k
251
+ # p.delete k
252
+ # attrs = FuelSDK.format_name_value_pairs k => v
253
+ # formated_attrs.concat attrs
254
+ # end
255
+ # end
256
+ # (p['Attributes'] ||= []).concat formated_attrs unless formated_attrs.empty?
257
+ # end
258
+ #
259
+
260
+ message = {
261
+ 'Objects' => properties,
262
+ :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + object_type) } }
263
+ }
264
+
265
+ if upsert
266
+ message['Options'] = {"SaveOptions" => {"SaveOption" => {"PropertyName"=> "*", "SaveAction" => "UpdateAdd"}}}
267
+ end
268
+
269
+ soap_request action, message
270
+ end
271
+
272
+ def soap_request action, message
273
+ response = action.eql?(:describe) ? DescribeResponse : SoapResponse
274
+ retried = false
275
+ begin
276
+ rsp = soap_client.call(action, :message => message)
277
+ rescue
278
+ raise if retried
279
+ retried = true
280
+ retry
281
+ end
282
+ response.new rsp, self
283
+ rescue
284
+ raise if rsp.nil?
285
+ response.new rsp, self
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,58 @@
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
+ module FuelSDK::Targeting
38
+ attr_accessor :access_token
39
+ attr_reader :endpoint
40
+
41
+ include FuelSDK::HTTPRequest
42
+
43
+ def endpoint
44
+ unless @endpoint
45
+ determine_stack
46
+ end
47
+ @endpoint
48
+ end
49
+
50
+ protected
51
+ def determine_stack
52
+ options = {'params' => {'access_token' => self.access_token}}
53
+ response = get("https://www.exacttargetapis.com/platform/v1/endpoints/soap", options)
54
+ @endpoint = response['url']
55
+ rescue => e
56
+ raise 'Unable to determine stack using: ' + e.message
57
+ end
58
+ end