exact-target-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +41 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +62 -0
  7. data/Rakefile +1 -0
  8. data/exact-target-api.gemspec +22 -0
  9. data/lib/exact-target-api.rb +43 -0
  10. data/lib/exact-target-api/base_object.rb +28 -0
  11. data/lib/exact-target-api/bounce_event.rb +8 -0
  12. data/lib/exact-target-api/campaign.rb +19 -0
  13. data/lib/exact-target-api/click_event.rb +8 -0
  14. data/lib/exact-target-api/client.rb +175 -0
  15. data/lib/exact-target-api/constructor.rb +34 -0
  16. data/lib/exact-target-api/content_area.rb +8 -0
  17. data/lib/exact-target-api/continue.rb +33 -0
  18. data/lib/exact-target-api/continue_rest.rb +24 -0
  19. data/lib/exact-target-api/create_wsdl.rb +53 -0
  20. data/lib/exact-target-api/cud_support.rb +19 -0
  21. data/lib/exact-target-api/cud_support_rest.rb +72 -0
  22. data/lib/exact-target-api/data_extension.rb +226 -0
  23. data/lib/exact-target-api/delete.rb +38 -0
  24. data/lib/exact-target-api/delete_rest.rb +18 -0
  25. data/lib/exact-target-api/describe.rb +25 -0
  26. data/lib/exact-target-api/email.rb +8 -0
  27. data/lib/exact-target-api/folder.rb +8 -0
  28. data/lib/exact-target-api/get.rb +64 -0
  29. data/lib/exact-target-api/get_rest.rb +25 -0
  30. data/lib/exact-target-api/get_support.rb +23 -0
  31. data/lib/exact-target-api/get_support_rest.rb +86 -0
  32. data/lib/exact-target-api/list.rb +68 -0
  33. data/lib/exact-target-api/list_subscriber.rb +10 -0
  34. data/lib/exact-target-api/open_event.rb +8 -0
  35. data/lib/exact-target-api/patch.rb +39 -0
  36. data/lib/exact-target-api/patch_rest.rb +19 -0
  37. data/lib/exact-target-api/post.rb +34 -0
  38. data/lib/exact-target-api/post_rest.rb +19 -0
  39. data/lib/exact-target-api/sent_event.rb +8 -0
  40. data/lib/exact-target-api/subscriber.rb +81 -0
  41. data/lib/exact-target-api/triggered_send.rb +15 -0
  42. data/lib/exact-target-api/unsub_event.rb +8 -0
  43. data/lib/exact-target-api/version.rb +3 -0
  44. metadata +113 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6cfa8a6154a2844221f392f18b3bd279c04926dc
4
+ data.tar.gz: eaedaa8b1f741d0a6492028726b06848fd772fd9
5
+ SHA512:
6
+ metadata.gz: 432df1a25e5e09a33fe0409d7864108f9dda8f465f0ae175b3bbdd1a6b42b7f22fcde7a9e3f8709979a9a1870ba714a5c6ca0459526a8428bbcaeb616653b9b2
7
+ data.tar.gz: 27a26d976407d8c93bab879bc6b383efc0ac1a5cb4dc8db1286ec246f2459523de569c136768e7242a729f7384c108d2884c5cbb48ed950d63470e885b7e9bdf
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in exact-target-api.gemspec
4
+ gemspec
@@ -0,0 +1,41 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ exact-target-api (0.0.1)
5
+ jwt (~> 0.1.8)
6
+ savon (~> 2.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ akami (1.2.0)
12
+ gyoku (>= 0.4.0)
13
+ nokogiri (>= 1.4.0)
14
+ builder (3.2.0)
15
+ gyoku (1.0.0)
16
+ builder (>= 2.1.2)
17
+ httpi (2.0.2)
18
+ rack
19
+ jwt (0.1.8)
20
+ multi_json (>= 1.5)
21
+ multi_json (1.7.3)
22
+ nokogiri (1.5.9)
23
+ nori (2.1.0)
24
+ rack (1.5.2)
25
+ savon (2.2.0)
26
+ akami (~> 1.2.0)
27
+ builder (>= 2.1.2)
28
+ gyoku (~> 1.0.0)
29
+ httpi (~> 2.0.2)
30
+ nokogiri (>= 1.4.0)
31
+ nori (~> 2.1.0)
32
+ wasabi (~> 3.1.0)
33
+ wasabi (3.1.0)
34
+ httpi (~> 2.0)
35
+ nokogiri (>= 1.4.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ exact-target-api!
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 thousandsofthem
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,62 @@
1
+ ExactTarget API wrapper
2
+ =====================
3
+
4
+ Usage example:
5
+
6
+ ```ruby
7
+ require 'rubygems'
8
+ require 'bundler/setup'
9
+ require 'exact-target-api'
10
+
11
+ config = {
12
+ clientid: 'xxxxxx',
13
+ clientsecret: 'yyyyyy',
14
+ appsignature: 'zzzzzz' # Optional
15
+ }
16
+
17
+ # All optional
18
+ options = {
19
+ debug: false,
20
+ wsdl: true,
21
+ jwt: params[:jwt]
22
+ }
23
+
24
+ client = ET::Client.new(config, options)
25
+
26
+
27
+ # Create new List
28
+ list = client.list.create(
29
+ ListName: "Test-List",
30
+ Description: "Test List",
31
+ Type: "Private"
32
+ )
33
+
34
+ puts "List ID is #{list.id}"
35
+
36
+ # Find a List
37
+ list2 = client.list.find(list.id)
38
+
39
+ # Create invalid subscriber
40
+ subscriber = client.subscriber.create(email: 'foo@bar.aaaa')
41
+ subscriber = client.subscriber.create(email: 'foo@bar.aaaa', list: list)
42
+ subscriber = client.subscriber.create(email: 'foo@bar.aaaa', list_id: 12345, name: "Foo Bar")
43
+
44
+ puts subscriber.code # 200
45
+ puts subscriber.status # false
46
+ puts subscriber.results # {:status_code=>"Error", :status_message=>"TriggeredSpamFilter", :ordinal_id=>"0", :error_code=>"12002", :new_id=>"0", :object=>{:partner_key=>nil, :object_id=>nil, :email_address=>"foo@bar.aaaa", :lists=>{:partner_key=>nil, :id=>"3488", :object_id=>nil}, :"@xsi:type"=>"Subscriber"}}
47
+
48
+ # Create valid subscriber
49
+ subscriber = client.subscriber.create(email: "RubySDK@bh.exacttarget.com", name: "Foo Bar", Description: "Some text")
50
+ puts subscriber.code # 200
51
+ puts subscriber.status # true
52
+ puts subscriber.results # {:status_code=>"OK", :status_message=>"Created Subscriber.", :ordinal_id=>"0", :new_id=>"24761785", :object=>{:partner_key=>nil, :id=>"24761785", :object_id=>nil, :email_address=>"RubySDK@bh.exacttarget.com", :attributes=>[{:name=>"name", :value=>"Foo Bar"}, {:name=>"Description", :value=>"Some text"}], :"@xsi:type"=>"Subscriber"}}
53
+
54
+ # Find a subscriber
55
+ subscriber = client.subscriber.find("RubySDK@bh.exacttarget.com")
56
+
57
+ puts subscriber.status # true
58
+ puts subscriber.results # {:partner_key=>nil, :object_id=>nil, :email_address=>"RubySDK@bh.exacttarget.com", :subscriber_key=>"RubySDK@bh.exacttarget.com", :status=>"Active", :"@xsi:type"=>"Subscriber"}
59
+
60
+
61
+
62
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'exact-target-api/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "exact-target-api"
8
+ gem.version = ET::VERSION
9
+ gem.authors = ["Alexander Shapiotko"]
10
+ gem.email = ["thousandsofthem@gmail.com"]
11
+ gem.description = "ExactTarget API wrapper"
12
+ gem.summary = "ExactTarget API wrapper"
13
+ gem.homepage = "https://github.com/BriteVerify/exact-target-api"
14
+
15
+ gem.add_dependency "savon", "~> 2.2.0"
16
+ gem.add_dependency "jwt", "~> 0.1.8"
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'open-uri'
3
+ require 'savon'
4
+ require 'date'
5
+ require 'json'
6
+ require 'yaml'
7
+ require 'jwt'
8
+
9
+ require "exact-target-api/version"
10
+ require "exact-target-api/base_object"
11
+ require "exact-target-api/get_support"
12
+ require "exact-target-api/bounce_event"
13
+ require "exact-target-api/get_support_rest"
14
+ require "exact-target-api/cud_support_rest"
15
+ require "exact-target-api/campaign"
16
+ require "exact-target-api/click_event"
17
+ require "exact-target-api/create_wsdl"
18
+ require "exact-target-api/client"
19
+ require "exact-target-api/constructor"
20
+ require "exact-target-api/cud_support"
21
+ require "exact-target-api/content_area"
22
+ require "exact-target-api/continue"
23
+ require "exact-target-api/continue_rest"
24
+ require "exact-target-api/data_extension"
25
+ require "exact-target-api/delete"
26
+ require "exact-target-api/delete_rest"
27
+ require "exact-target-api/describe"
28
+ require "exact-target-api/email"
29
+ require "exact-target-api/folder"
30
+ require "exact-target-api/get"
31
+ require "exact-target-api/get_rest"
32
+ require "exact-target-api/list"
33
+ require "exact-target-api/list_subscriber"
34
+ require "exact-target-api/open_event"
35
+ require "exact-target-api/patch"
36
+ require "exact-target-api/patch_rest"
37
+ require "exact-target-api/post"
38
+ require "exact-target-api/post_rest"
39
+ require "exact-target-api/sent_event"
40
+ require "exact-target-api/subscriber"
41
+ require "exact-target-api/triggered_send"
42
+ require "exact-target-api/unsub_event"
43
+
@@ -0,0 +1,28 @@
1
+ module ET
2
+ class BaseObject
3
+ attr_accessor :props, :client
4
+ attr_reader :obj, :lastRequestID, :endpoint
5
+
6
+ def initialize
7
+ @props = nil
8
+ @filter = nil
9
+ @lastRequestID = nil
10
+ @endpoint = nil
11
+ end
12
+
13
+
14
+ def stringify_keys!(params)
15
+ params.keys.each do |key|
16
+ params[key.to_s] = params.delete(key)
17
+ end
18
+ params
19
+ end
20
+
21
+ def symbolize_keys!(params)
22
+ params.keys.each do |key|
23
+ params[key.to_sym] = params.delete(key)
24
+ end
25
+ params
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ module ET
2
+ class BounceEvent < ET::GetSupport
3
+ def initialize
4
+ super
5
+ @obj = 'BounceEvent'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ module ET
2
+ class Campaign < ET::CUDSupportRest
3
+ def initialize
4
+ super
5
+ @endpoint = 'https://www.exacttargetapis.com/hub/v1/campaigns/{id}'
6
+ @urlProps = ["id"]
7
+ @urlPropsRequired = []
8
+ end
9
+
10
+ class Asset < ET::CUDSupportRest
11
+ def initialize
12
+ super
13
+ @endpoint = 'https://www.exacttargetapis.com/hub/v1/campaigns/{id}/assets/{assetId}'
14
+ @urlProps = ["id", "assetId"]
15
+ @urlPropsRequired = ["id"]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ module ET
2
+ class ClickEvent < ET::GetSupport
3
+ def initialize
4
+ super
5
+ @obj = 'ClickEvent'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,175 @@
1
+ require 'tmpdir'
2
+
3
+ module ET
4
+ class Client < ET::CreateWSDL
5
+ attr_accessor :auth, :ready, :status, :debug, :authToken
6
+ attr_reader :authTokenExpiration, :internalAuthToken, :wsdlLoc, :clientId, :clientSecret, :soapHeader, :authObj, :path, :appsignature, :stackID, :refreshKey
7
+
8
+ def initialize(config, options = {})
9
+ load_config(config)
10
+ symbolize_keys!(options)
11
+
12
+ get_wsdl = options.has_key?(:wsdl) ? options[:wsdl] : true
13
+
14
+ @debug = options[:debug]
15
+
16
+ @path = Dir.tmpdir
17
+
18
+ begin
19
+ if get_wsdl
20
+ super(@path)
21
+ end
22
+
23
+ if options[:jwt]
24
+ jwt = JWT.decode(options[:jwt], @appsignature, true)
25
+ @authToken = jwt['request']['user']['oauthToken']
26
+ @authTokenExpiration = [Time.at(jwt['exp']), Time.now + jwt['request']['user']['expiresIn']].min
27
+ @internalAuthToken = jwt['request']['user']['internalOauthToken']
28
+ @refreshKey = jwt['request']['user']['refreshToken']
29
+
30
+ self.determineStack
31
+
32
+ @authObj = {'oAuth' => {'oAuthToken' => @internalAuthToken}}
33
+ @authObj[:attributes!] = { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }}
34
+
35
+ @auth = Savon.client(soap_header: @authObj,
36
+ wsdl: File.read(wsdl_file(@path)),
37
+ endpoint: @endpoint,
38
+ wsse_auth: ["*", "*"],
39
+ raise_errors: false,
40
+ log: @debug,
41
+ open_timeout: 180,
42
+ read_timeout: 180)
43
+ end
44
+ refreshToken
45
+ rescue
46
+ raise
47
+ end
48
+
49
+ @ready = @auth.operations.length > 0 && @status >= 200 && @status <= 400
50
+ end
51
+
52
+ def refreshToken(force = nil)
53
+ #If we don't already have a token or the token expires within 5 min(300 seconds), get one
54
+ if force || @authToken.nil? || Time.now + 300 > @authTokenExpiration
55
+ begin
56
+ uri = URI.parse("https://auth.exacttargetapis.com/v1/requestToken?legacy=1")
57
+ http = Net::HTTP.new(uri.host, uri.port)
58
+ http.use_ssl = true
59
+ request = Net::HTTP::Post.new(uri.request_uri)
60
+
61
+ jsonPayload = {clientId: @clientId, clientSecret: @clientSecret}#, accessType: 'offline'}
62
+ # Pass in the refreshKey if we have it
63
+ jsonPayload[:refreshToken] = @refreshKey if @refreshKey
64
+
65
+ request.body = jsonPayload.to_json
66
+ request.add_field "Content-Type", "application/json"
67
+ tokenResponse = JSON.parse(http.request(request).body)
68
+
69
+ if tokenResponse['accessToken'].nil?
70
+ raise 'Unable to validate App Keys(ClientID/ClientSecret) provided: ' + http.request(request).body
71
+ end
72
+
73
+ @authToken = tokenResponse['accessToken']
74
+ @authTokenExpiration = Time.new + tokenResponse['expiresIn']
75
+ @internalAuthToken = tokenResponse['legacyToken']
76
+ if tokenResponse["refreshToken"]
77
+ @refreshKey = tokenResponse['refreshToken']
78
+ end
79
+
80
+
81
+ self.determineStack if @endpoint.nil?
82
+
83
+ @authObj = {'oAuth' => {'oAuthToken' => @internalAuthToken}}
84
+ @authObj[:attributes!] = {'oAuth' => {'xmlns' => 'http://exacttarget.com' }}
85
+
86
+ @auth = Savon.client(soap_header: @authObj,
87
+ wsdl: File.read(wsdl_file(@path)),
88
+ endpoint: @endpoint,
89
+ wsse_auth: ["*", "*"],
90
+ raise_errors: false,
91
+ log: @debug)
92
+
93
+
94
+ rescue Exception => e
95
+ raise 'Unable to validate App Keys(ClientID/ClientSecret) provided: ' + e.message
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ def list
102
+ ET::List.new(self)
103
+ end
104
+
105
+ def subscriber
106
+ ET::Subscriber.new(self)
107
+ end
108
+
109
+ #def AddSubscriberToList(emailAddress, listIDs, subscriberKey = nil)
110
+ # newSub = ET::Subscriber.new
111
+ # newSub.authStub = self
112
+ # lists = []
113
+ #
114
+ # listIDs.each{ |p|
115
+ # lists.push({"ID"=> p})
116
+ # }
117
+ #
118
+ # newSub.props = {"EmailAddress" => emailAddress, "Lists" => lists}
119
+ # if !subscriberKey.nil?
120
+ # newSub.props['SubscriberKey'] = subscriberKey
121
+ # end
122
+ #
123
+ # # Try to add the subscriber
124
+ # postResponse = newSub.post
125
+ #
126
+ # if !postResponse.status
127
+ # # If the subscriber already exists in the account then we need to do an update.
128
+ # # Update Subscriber On List
129
+ # if postResponse.results[0][:error_code] == "12014"
130
+ # patchResponse = newSub.patch
131
+ # return patchResponse
132
+ # end
133
+ # end
134
+ # postResponse
135
+ #end
136
+
137
+ #def CreateDataExtensions(dataExtensionDefinitions)
138
+ # newDEs = ET::DataExtension.new
139
+ # newDEs.authStub = self
140
+ #
141
+ # newDEs.props = dataExtensionDefinitions
142
+ # newDEs.post
143
+ #end
144
+
145
+
146
+ protected
147
+
148
+
149
+ def load_config(config)
150
+ symbolize_keys!(config)
151
+
152
+ @clientId = config[:clientid] || raise("Please provide ClientID")
153
+ @clientSecret = config[:clientsecret] || raise("Please provide Client Secret")
154
+ @appsignature = config[:appsignature]
155
+ @wsdl = config[:defaultwsdl] || 'https://webservice.exacttarget.com/etframework.wsdl'
156
+ end
157
+
158
+ def determineStack
159
+ begin
160
+ uri = URI.parse("https://www.exacttargetapis.com/platform/v1/endpoints/soap?access_token=" + @authToken)
161
+ http = Net::HTTP.new(uri.host, uri.port)
162
+
163
+ http.use_ssl = true
164
+
165
+ request = Net::HTTP::Get.new(uri.request_uri)
166
+
167
+ contextResponse = JSON.parse(http.request(request).body)
168
+ @endpoint = contextResponse['url']
169
+
170
+ rescue Exception => e
171
+ raise 'Unable to determine stack using /platform/v1/tokenContext: ' + e.message
172
+ end
173
+ end
174
+ end
175
+ end