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,116 @@
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 'open-uri'
38
+ require 'net/https'
39
+ require 'json'
40
+
41
+ module FuelSDK
42
+
43
+ class HTTPResponse < FuelSDK::Response
44
+
45
+ def initialize raw, client, request
46
+ super raw, client
47
+ @request = request
48
+ end
49
+
50
+ def continue
51
+ rsp = nil
52
+ if more?
53
+ @request['options']['page'] = @results['page'].to_i + 1
54
+ rsp = unpack @client.rest_get(@request['url'], @request['options'])
55
+ else
56
+ puts 'No more data'
57
+ end
58
+
59
+ rsp
60
+ end
61
+
62
+ def [] key
63
+ @results[key]
64
+ end
65
+
66
+ private
67
+ def unpack raw
68
+ @code = raw.code.to_i
69
+ @message = raw.message
70
+ @body = JSON.parse(raw.body) rescue {}
71
+ @results = @body
72
+ @more = ((@results['count'] || @results['totalCount']) > @results['page'] * @results['pageSize']) rescue false
73
+ @success = @message == 'OK'
74
+ end
75
+
76
+ # by default try everything against results
77
+ def method_missing method, *args, &block
78
+ @results.send(method, *args, &block)
79
+ end
80
+ end
81
+
82
+ module HTTPRequest
83
+
84
+ request_methods = ['get', 'post', 'patch', 'delete']
85
+ request_methods.each do |method|
86
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
87
+ def #{method}(url, options={}) # def post(url, options)
88
+ request Net::HTTP::#{method.capitalize}, url, options # request Net::HTTP::Post, url, options
89
+ end # end
90
+ EOT
91
+ end
92
+
93
+ private
94
+
95
+ def generate_uri(url, params=nil)
96
+ uri = URI.parse(url)
97
+ uri.query = URI.encode_www_form(params) if params
98
+ uri
99
+ end
100
+
101
+ def request(method, url, options={})
102
+ uri = generate_uri url, options['params']
103
+
104
+ http = Net::HTTP.new(uri.host, uri.port)
105
+ http.use_ssl = true
106
+
107
+ data = options['data']
108
+ _request = method.new uri.request_uri
109
+ _request.body = data.to_json if data
110
+ _request.content_type = options['content_type'] if options['content_type']
111
+ response = http.request(_request)
112
+
113
+ HTTPResponse.new(response, self, :url => url, :options => options)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,757 @@
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 Objects
39
+ module Soap
40
+ module Read
41
+ attr_accessor :filter
42
+ def get _id=nil
43
+ client.soap_get _id||id, properties, filter
44
+ end
45
+
46
+ def info
47
+ client.soap_describe id
48
+ end
49
+ end
50
+
51
+ module CUD #create, update, delete
52
+ def post
53
+ if self.respond_to?('folder_property') && !self.folder_id.nil?
54
+ properties[self.folder_property] = self.folder_id
55
+ elsif self.respond_to?('folder_property') && !self.folder_property.nil? && !client.package_name.nil? then
56
+ if client.package_folders.nil? then
57
+ getPackageFolder = ET_Folder.new
58
+ getPackageFolder.authStub = client
59
+ getPackageFolder.properties = ["ID", "ContentType"]
60
+ getPackageFolder.filter = {"Property" => "Name", "SimpleOperator" => "equals", "Value" => client.package_name}
61
+ resultPackageFolder = getPackageFolder.get
62
+ if resultPackageFolder.status then
63
+ client.package_folders = {}
64
+ resultPackageFolder.results.each do |value|
65
+ client.package_folders[value[:content_type]] = value[:id]
66
+ end
67
+ else
68
+ raise "Unable to retrieve folders from account due to: #{resultPackageFolder.message}"
69
+ end
70
+ end
71
+
72
+ if !client.package_folders.has_key?(self.folder_media_type) then
73
+ if client.parentFolders.nil? then
74
+ parentFolders = ET_Folder.new
75
+ parentFolders.authStub = client
76
+ parentFolders.properties = ["ID", "ContentType"]
77
+ parentFolders.filter = {"Property" => "ParentFolder.ID", "SimpleOperator" => "equals", "Value" => "0"}
78
+ resultParentFolders = parentFolders.get
79
+ if resultParentFolders.status then
80
+ client.parent_folders = {}
81
+ resultParentFolders.results.each do |value|
82
+ client.parent_folders[value[:content_type]] = value[:id]
83
+ end
84
+ else
85
+ raise "Unable to retrieve folders from account due to: #{resultParentFolders.message}"
86
+ end
87
+ end
88
+
89
+ newFolder = ET_Folder.new
90
+ newFolder.authStub = client
91
+ newFolder.properties = {"Name" => client.package_name, "Description" => client.package_name, "ContentType"=> self.folder_media_type, "IsEditable"=>"true", "ParentFolder" => {"ID" => client.parentFolders[self.folder_media_type]}}
92
+ folderResult = newFolder.post
93
+ if folderResult.status then
94
+ client.package_folders[self.folder_media_type] = folderResult.results[0][:new_id]
95
+ else
96
+ raise "Unable to create folder for Post due to: #{folderResult.message}"
97
+ end
98
+
99
+ end
100
+ properties[self.folder_property] = client.package_folders[self.folder_media_type]
101
+ end
102
+ client.soap_post id, properties
103
+ end
104
+
105
+ def patch
106
+ client.soap_patch id, properties
107
+ end
108
+
109
+ def delete
110
+ client.soap_delete id, properties
111
+ end
112
+ end
113
+
114
+ module Upsert
115
+ def put
116
+ client.soap_put id, properties
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ module Rest
123
+ module Read
124
+ def get
125
+ client.rest_get id, properties
126
+ end
127
+ end
128
+
129
+ module CUD
130
+ def post
131
+ client.rest_post id, properties
132
+ end
133
+
134
+ def patch
135
+ client.rest_patch id, properties
136
+ end
137
+
138
+ def delete
139
+ client.rest_delete id, properties
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ class Base
146
+ attr_accessor :properties, :client
147
+ attr_reader :id
148
+
149
+ alias props= properties= # backward compatibility
150
+ alias authStub= client= # backward compatibility
151
+
152
+ def properties
153
+ #@properties = [@properties].compact unless @properties.kind_of? Array
154
+ @properties
155
+ end
156
+
157
+ #Backwards compatibility
158
+ def props
159
+ @properties
160
+ end
161
+
162
+ def id
163
+ self.class.id
164
+ end
165
+
166
+ class << self
167
+ def id
168
+ self.name.split('::').pop
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ class BounceEvent < Objects::Base
175
+ attr_accessor :get_since_last_batch
176
+ include Objects::Soap::Read
177
+ end
178
+
179
+ class ClickEvent < Objects::Base
180
+ attr_accessor :get_since_last_batch
181
+ include Objects::Soap::Read
182
+ end
183
+
184
+ class ContentArea < Objects::Base
185
+ include Objects::Soap::Read
186
+ include Objects::Soap::CUD
187
+ attr_accessor :folder_id
188
+
189
+ def folder_property
190
+ 'CategoryID'
191
+ end
192
+
193
+ def folder_media_type
194
+ 'content'
195
+ end
196
+ end
197
+
198
+ class DataFolder < Objects::Base
199
+ include Objects::Soap::Read
200
+ include Objects::Soap::CUD
201
+ end
202
+
203
+ class Folder < DataFolder
204
+ class << self
205
+ def id
206
+ DataFolder.id
207
+ end
208
+ end
209
+ end
210
+
211
+ class Email < Objects::Base
212
+ include Objects::Soap::Read
213
+ include Objects::Soap::CUD
214
+ attr_accessor :folder_id
215
+
216
+ def folder_property
217
+ 'CategoryID'
218
+ end
219
+
220
+ def folder_media_type
221
+ 'email'
222
+ end
223
+
224
+ class SendDefinition < Objects::Base
225
+ include Objects::Soap::Read
226
+ include Objects::Soap::CUD
227
+ attr_accessor :folder_id
228
+
229
+ def id
230
+ 'EmailSendDefinition'
231
+ end
232
+
233
+ def folder_property
234
+ 'CategoryID'
235
+ end
236
+
237
+ def folder_media_type
238
+ 'userinitiatedsends'
239
+ end
240
+
241
+
242
+ def send
243
+ perform_response = client.soap_perform id, 'start' , properties
244
+ if perform_response.status then
245
+ @last_task_id = perform_response.results[0][:result][:task][:id]
246
+ end
247
+ perform_response
248
+ end
249
+
250
+ def status
251
+ client.soap_get "Send", ['ID','CreatedDate', 'ModifiedDate', 'Client.ID', 'Email.ID', 'SendDate','FromAddress','FromName','Duplicates','InvalidAddresses','ExistingUndeliverables','ExistingUnsubscribes','HardBounces','SoftBounces','OtherBounces','ForwardedEmails','UniqueClicks','UniqueOpens','NumberSent','NumberDelivered','NumberTargeted','NumberErrored','NumberExcluded','Unsubscribes','MissingAddresses','Subject','PreviewURL','SentDate','EmailName','Status','IsMultipart','SendLimit','SendWindowOpen','SendWindowClose','BCCEmail','EmailSendDefinition.ObjectID','EmailSendDefinition.CustomerKey'], {'Property' => 'ID','SimpleOperator' => 'equals','Value' => @last_task_id}
252
+ end
253
+
254
+ private
255
+ attr_accessor :last_task_id
256
+
257
+ end
258
+ end
259
+
260
+
261
+
262
+ class Import < Objects::Base
263
+ include Objects::Soap::Read
264
+ include Objects::Soap::CUD
265
+
266
+
267
+ def id
268
+ 'ImportDefinition'
269
+ end
270
+
271
+ def post
272
+ originalProp = properties
273
+ cleanProps
274
+ obj = super
275
+ properties = originalProp
276
+ return obj
277
+ end
278
+
279
+ def patch
280
+ originalProp = properties
281
+ cleanProps
282
+ obj = super
283
+ properties = originalProp
284
+ return obj
285
+ end
286
+
287
+ def start
288
+ perform_response = client.soap_perform id, 'start' , properties
289
+ if perform_response.status then
290
+ @last_task_id = perform_response.results[0][:result][:task][:id]
291
+ end
292
+ perform_response
293
+ end
294
+
295
+ def status
296
+ client.soap_get "ImportResultsSummary", ['ImportDefinitionCustomerKey','TaskResultID','ImportStatus','StartDate','EndDate','DestinationID','NumberSuccessful','NumberDuplicated','NumberErrors','TotalRows','ImportType'], {'Property' => 'TaskResultID','SimpleOperator' => 'equals','Value' => @last_task_id}
297
+ end
298
+
299
+ private
300
+ attr_accessor :last_task_id
301
+
302
+ def cleanProps
303
+ # If the ID property is specified for the destination then it must be a list import
304
+ if properties.has_key?('DestinationObject') then
305
+ if properties['DestinationObject'].has_key?('ID') then
306
+ properties[:attributes!] = { 'DestinationObject' => { 'xsi:type' => 'tns:List'}}
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+
313
+ class List < Objects::Base
314
+ include Objects::Soap::Read
315
+ include Objects::Soap::CUD
316
+ attr_accessor :folder_id
317
+
318
+ def folder_property
319
+ 'Category'
320
+ end
321
+
322
+ def folder_media_type
323
+ 'list'
324
+ end
325
+
326
+ class Subscriber < Objects::Base
327
+ include Objects::Soap::Read
328
+ def id
329
+ 'ListSubscriber'
330
+ end
331
+ end
332
+ end
333
+
334
+ class OpenEvent < Objects::Base
335
+ attr_accessor :get_since_last_batch
336
+ include Objects::Soap::Read
337
+ end
338
+
339
+ class SentEvent < Objects::Base
340
+ attr_accessor :get_since_last_batch
341
+ include Objects::Soap::Read
342
+ end
343
+
344
+ class Subscriber < Objects::Base
345
+ include Objects::Soap::Read
346
+ include Objects::Soap::CUD
347
+ include Objects::Soap::Upsert
348
+ end
349
+
350
+ class UnsubEvent < Objects::Base
351
+ attr_accessor :get_since_last_batch
352
+ include Objects::Soap::Read
353
+ end
354
+
355
+ class ProfileAttribute < Objects::Base
356
+ def get
357
+ client.soap_describe "Subscriber"
358
+ end
359
+
360
+ def post
361
+ client.soap_configure "PropertyDefinition","create", properties
362
+ end
363
+
364
+ def delete
365
+ client.soap_configure "PropertyDefinition","delete", properties
366
+ end
367
+
368
+ def patch
369
+ client.soap_configure "PropertyDefinition","update", properties
370
+ end
371
+ end
372
+
373
+ class TriggeredSend < Objects::Base
374
+ include Objects::Soap::Read
375
+ include Objects::Soap::CUD
376
+ attr_accessor :folder_id, :subscribers
377
+ def id
378
+ 'TriggeredSendDefinition'
379
+ end
380
+
381
+ def folder_property
382
+ 'CategoryID'
383
+ end
384
+
385
+ def folder_media_type
386
+ 'triggered_send'
387
+ end
388
+
389
+ def send
390
+ if self.properties.is_a? Array then
391
+ tscall = []
392
+ self.properties.each{ |p|
393
+ tscall.push({"TriggeredSendDefinition" => {"CustomerKey" => p["CustomerKey"]}, "Subscribers" => p["Subscribers"]})
394
+ }
395
+ else
396
+ tscall = {"TriggeredSendDefinition" => self.properties, "Subscribers" => @subscribers}
397
+ end
398
+ client.soap_post 'TriggeredSend', tscall
399
+ end
400
+ end
401
+
402
+ class DataExtension < Objects::Base
403
+ include Objects::Soap::Read
404
+ include Objects::Soap::CUD
405
+ attr_accessor :fields, :folder_id
406
+
407
+ def folder_property
408
+ 'CategoryID'
409
+ end
410
+
411
+ def folder_media_type
412
+ 'dataextension'
413
+ end
414
+
415
+ alias columns= fields= # backward compatibility
416
+
417
+ def post
418
+ munge_fields self.properties
419
+ super
420
+ end
421
+
422
+ def patch
423
+ munge_fields self.properties
424
+ super
425
+ end
426
+
427
+ class Column < Objects::Base
428
+ include Objects::Soap::Read
429
+ def id
430
+ 'DataExtensionField'
431
+ end
432
+ def get
433
+ if filter and filter.kind_of? Hash and \
434
+ filter.include? 'Property' and filter['Property'] == 'CustomerKey'
435
+ filter['Property'] = 'DataExtension.CustomerKey'
436
+ end
437
+ super
438
+ end
439
+ end
440
+
441
+ class Row < Objects::Base
442
+ include Objects::Soap::Read
443
+ include Objects::Soap::CUD
444
+ include Objects::Soap::Upsert
445
+
446
+ attr_accessor :name, :customer_key
447
+
448
+ # backward compatibility
449
+ alias Name= name=
450
+ alias CustomerKey= customer_key=
451
+
452
+ def id
453
+ 'DataExtensionObject'
454
+ end
455
+
456
+ def get
457
+ super "#{id}[#{name}]"
458
+ end
459
+
460
+ def name
461
+ unless @name
462
+ retrieve_required
463
+ end
464
+ @name
465
+ end
466
+
467
+ def customer_key
468
+ unless @customer_key
469
+ retrieve_required
470
+ end
471
+ @customer_key
472
+ end
473
+
474
+ def post
475
+ munge_properties self.properties
476
+ super
477
+ end
478
+
479
+ def patch
480
+ munge_properties self.properties
481
+ super
482
+ end
483
+
484
+ def put
485
+ munge_properties self.properties
486
+ super
487
+ end
488
+
489
+ def delete
490
+ munge_keys self.properties
491
+ super
492
+ end
493
+
494
+ private
495
+ #::TODO::
496
+ # opportunity for meta programming here... but need to get this out the door
497
+ def munge_keys d
498
+ if d.kind_of? Array
499
+ d.each do |o|
500
+
501
+ next if explicit_keys(o) && explicit_customer_key(o)
502
+
503
+ formatted = []
504
+ o['CustomerKey'] = customer_key unless explicit_customer_key o
505
+ unless explicit_properties(o)
506
+ o.each do |k, v|
507
+ next if k == 'CustomerKey'
508
+ formatted.concat FuelSDK.format_name_value_pairs k => v
509
+ o.delete k
510
+ end
511
+ o['Keys'] = {'Key' => formatted }
512
+ end
513
+ end
514
+ else
515
+ formatted = []
516
+ d.each do |k, v|
517
+ next if k == 'CustomerKey'
518
+ formatted.concat FuelSDK.format_name_value_pairs k => v
519
+ d.delete k
520
+ end
521
+ d['CustomerKey'] = customer_key
522
+ d['Keys'] = {'Key' => formatted }
523
+ end
524
+ end
525
+
526
+ def explicit_keys h
527
+ h['Keys'] and h['Keys']['Key']
528
+ end
529
+
530
+ def munge_properties d
531
+ if d.kind_of? Array
532
+ d.each do |o|
533
+ next if explicit_properties(o) && explicit_customer_key(o)
534
+
535
+ formatted = []
536
+ o['CustomerKey'] = customer_key unless explicit_customer_key o
537
+ unless explicit_properties(o)
538
+ o.each do |k, v|
539
+ next if k == 'CustomerKey'
540
+ formatted.concat FuelSDK.format_name_value_pairs k => v
541
+ o.delete k
542
+ end
543
+ o['Properties'] = {'Property' => formatted }
544
+ end
545
+ end
546
+ else
547
+ formatted = []
548
+ d.each do |k, v|
549
+ formatted.concat FuelSDK.format_name_value_pairs k => v
550
+ d.delete k
551
+ end
552
+ d['CustomerKey'] = customer_key
553
+ d['Properties'] = {'Property' => formatted }
554
+ end
555
+ end
556
+
557
+ def explicit_properties h
558
+ h['Properties'] and h['Properties']['Property']
559
+ end
560
+
561
+ def explicit_customer_key h
562
+ h['CustomerKey']
563
+ end
564
+
565
+ def retrieve_required
566
+ # have to use instance variables so we don't recursivelly retrieve_required
567
+ if !@name && !@customer_key
568
+ raise 'Unable to process DataExtension::Row ' \
569
+ 'request due to missing CustomerKey and Name'
570
+ end
571
+ if !@name || !@customer_key
572
+ filter = {
573
+ 'Property' => @name.nil? ? 'CustomerKey' : 'Name',
574
+ 'SimpleOperator' => 'equals',
575
+ 'Value' => @customer_key || @name
576
+ }
577
+ rsp = client.soap_get 'DataExtension', ['Name', 'CustomerKey'], filter
578
+ if rsp.success? && rsp.results.count == 1
579
+ self.name = rsp.results.first[:name]
580
+ self.customer_key = rsp.results.first[:customer_key]
581
+ else
582
+ raise 'Unable to process DataExtension::Row'
583
+ end
584
+ end
585
+ end
586
+ end
587
+
588
+ private
589
+
590
+ def munge_fields d
591
+ # maybe one day will make it smart enough to zip properties and fields if count is same?
592
+ if d.kind_of? Array and d.count > 1 and (fields and !fields.empty?)
593
+ # we could map the field to all DataExtensions, but lets make user be explicit.
594
+ # if they are going to use fields attribute properties should
595
+ # be a single DataExtension Defined in a Hash
596
+ raise 'Unable to handle muliple DataExtension definitions and a field definition'
597
+ end
598
+
599
+ if d.kind_of? Array
600
+ d.each do |de|
601
+ if (explicit_fields(de) and (de['columns'] || de['fields'] || has_fields)) or
602
+ (de['columns'] and (de['fields'] || has_fields)) or
603
+ (de['fields'] and has_fields)
604
+ raise 'Fields are defined in too many ways. Please only define once.' # ahhh what, to do...
605
+ end
606
+
607
+ # let users who chose, to define fields explicitly within the hash definition
608
+ next if explicit_fields de
609
+
610
+ de['Fields'] = {'Field' => de['columns'] || de['fields'] || fields}
611
+ # sanitize
612
+
613
+ raise 'DataExtension needs atleast one field.' unless de['Fields']['Field']
614
+ end
615
+ else
616
+ self.properties['Fields'] = {'Field' => self.properties['columns'] || self.properties['fields'] || fields}
617
+ raise 'DataExtension needs atleast one field.' unless self.properties['Fields']['Field']
618
+ self.properties.delete 'columns'
619
+ self.properties.delete 'fields'
620
+ end
621
+ end
622
+
623
+ def explicit_fields h
624
+ h['Fields'] and h['Fields']['Field']
625
+ end
626
+
627
+ def has_fields
628
+ fields and !fields.empty?
629
+ end
630
+ end
631
+
632
+ class Campaign < Objects::Base
633
+ include Objects::Rest::Read
634
+ include Objects::Rest::CUD
635
+
636
+ def properties
637
+ @properties ||= {}
638
+ @properties.merge! 'id' => '' unless @properties.include? 'id'
639
+ @properties
640
+ end
641
+
642
+ def id
643
+ "https://www.exacttargetapis.com/hub/v1/campaigns/%{id}"
644
+ end
645
+
646
+ class Asset < Objects::Base
647
+ include Objects::Rest::Read
648
+ include Objects::Rest::CUD
649
+
650
+ def properties
651
+ @properties ||= {}
652
+ @properties.merge! 'assetId' => '' unless @properties.include? 'assetId'
653
+ @properties
654
+ end
655
+
656
+ def id
657
+ 'https://www.exacttargetapis.com/hub/v1/campaigns/%{id}/assets/%{assetId}'
658
+ end
659
+ end
660
+ end
661
+
662
+ # Direct Verb Access Section
663
+
664
+ class Get < Objects::Base
665
+ include Objects::Soap::Read
666
+ attr_accessor :id
667
+
668
+ def initialize client, id, properties, filter
669
+ self.properties = properties
670
+ self.filter = filter
671
+ self.client = client
672
+ self.id = id
673
+ end
674
+
675
+ def get
676
+ super id
677
+ end
678
+
679
+ class << self
680
+ def new client, id, properties=nil, filter=nil
681
+ o = self.allocate
682
+ o.send :initialize, client, id, properties, filter
683
+ return o.get
684
+ end
685
+ end
686
+ end
687
+
688
+ class Post < Objects::Base
689
+ include Objects::Soap::CUD
690
+ attr_accessor :id
691
+
692
+ def initialize client, id, properties
693
+ self.properties = properties
694
+ self.client = client
695
+ self.id = id
696
+ end
697
+
698
+ def post
699
+ super
700
+ end
701
+
702
+ class << self
703
+ def new client, id, properties=nil
704
+ o = self.allocate
705
+ o.send :initialize, client, id, properties
706
+ return o.post
707
+ end
708
+ end
709
+ end
710
+
711
+ class Delete < Objects::Base
712
+ include Objects::Soap::CUD
713
+ attr_accessor :id
714
+
715
+ def initialize client, id, properties
716
+ self.properties = properties
717
+ self.client = client
718
+ self.id = id
719
+ end
720
+
721
+ def delete
722
+ super
723
+ end
724
+
725
+ class << self
726
+ def new client, id, properties=nil
727
+ o = self.allocate
728
+ o.send :initialize, client, id, properties
729
+ return o.delete
730
+ end
731
+ end
732
+ end
733
+
734
+ class Patch < Objects::Base
735
+ include Objects::Soap::CUD
736
+ attr_accessor :id
737
+
738
+ def initialize client, id, properties
739
+ self.properties = properties
740
+ self.client = client
741
+ self.id = id
742
+ end
743
+
744
+ def patch
745
+ super
746
+ end
747
+
748
+ class << self
749
+ def new client, id, properties=nil
750
+ o = self.allocate
751
+ o.send :initialize, client, id, properties
752
+ return o.patch
753
+ end
754
+ end
755
+ end
756
+
757
+ end