etapi 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source(:rubygems)
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ ExactTarget API Wrapper
2
+ =======================
3
+
4
+ ETAPI is an ExactTarget API wrapper for XML calls.
5
+
6
+ Documentation
7
+ ------------
8
+ [Wiki](https://github.com/Phiction/etapi/wiki)
9
+
10
+ TODO
11
+ ====
12
+
13
+ Subscriber Management
14
+ ---
15
+ `subscriber_add` : add s4 `:account_id`, add `:status`
16
+ `subscriber_edit` : add s4 `:account_id`, add `:status`
17
+ `subscriber_retrieve` : add s4 `:account_id`, add `:status`
18
+ `subscriber_retrieve_from_list`
19
+ `subscriber_retrieve_from_list` : add s4 `:account_id`, add `:status`
20
+ `subscriber_retrieve_lists`
21
+ `subscriber_retrieve_lists` : add s4 `:account_id`, add `:status`
22
+ `subscriber_unsubscribe_master` : multiple email addresses
23
+
24
+ List Management
25
+ ---
26
+ `list_retrieve_subscribers` : add s4 `:account_id`, add `:status`
27
+
28
+ Email Management
29
+ ---
30
+ `email_retrieve_body` : have access to sub accounts?
31
+
32
+ XML
33
+ ===
34
+ Any other XML calls available will be added by request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/etapi.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $:.unshift lib unless $:.include? lib
3
+
4
+ require "etapi/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "etapi"
8
+ s.version = ETAPI::Version
9
+ s.authors = ["Chris McGrath"]
10
+ s.email = ["mcgrath.chris@gmail.com"]
11
+ s.homepage = %q{http://github.com/phiction/etapi}
12
+ s.summary = %q{Ruby Wrapper for Exact Target's APIs}
13
+ s.description = %q{This is an attempt to make integrating easier with Exact Target's XML APIs.}
14
+
15
+ s.rubyforge_project = "etapi"
16
+
17
+ s.add_dependency("builder", ">= 2.1.2")
18
+ s.add_dependency("nokogiri", ">= 1.4.1")
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.require_path = "lib"
22
+ end
@@ -0,0 +1,70 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def build_call(type, method, *args)
6
+
7
+ options = args.extract_options!
8
+ ignore_parse = options[:ignore_parse] || false
9
+
10
+ data = ""
11
+ xml = Builder::XmlMarkup.new(:target => data, :indent => 2)
12
+ xml.instruct!
13
+ xml.exacttarget do
14
+ xml.authorization do
15
+ xml.username @username
16
+ xml.password @password
17
+ end
18
+ xml.system do
19
+ xml.system_name type
20
+ xml.action method
21
+ for parameter in @parameters
22
+ if parameter[0] == "values"
23
+ xml.values do
24
+ parameter[1].each do |key, value|
25
+ eval("xml.#{key.gsub(/\s/, '__')} '#{value}'")
26
+ end
27
+ end
28
+ else
29
+ if parameter[1].is_a?(Hash)
30
+ xml.tag!(parameter[0]) do
31
+ parameter[1].each do |key, value|
32
+ eval("xml.#{key.gsub(/\s/, '__')} '#{value}'")
33
+ end
34
+ end
35
+ else
36
+ eval("xml.#{parameter[0]} '#{parameter[1]}'")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ data_encoded = "qf=xml&xml=" + url_encode(data)
44
+ response = @api_url.post(@api_uri.path, data_encoded, @headers.merge('Content-length' => data_encoded.length.to_s))
45
+ check_response(response)
46
+ ignore_parse ? response.read_body : Nokogiri::XML::Document.parse(response.read_body)
47
+
48
+ end
49
+
50
+ private
51
+
52
+ def print_xml(obj)
53
+ require "rexml/document"
54
+ doc = REXML::Document.new(obj.http.raw_body)
55
+ out = ""
56
+ doc.write(out, 1)
57
+ out
58
+ end
59
+
60
+ def print_full_xml(obj)
61
+ require "rexml/document"
62
+ doc = REXML::Document.new(obj)
63
+ out = ""
64
+ doc.write(out, 1)
65
+ out
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,33 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def email_retrieve_body(*args)
6
+
7
+ # options
8
+ options = args.extract_options!
9
+ @email_id = options[:email_id]
10
+
11
+ # check for required options
12
+ required_options = ["email_id"]
13
+ return false unless check_required(required_options)
14
+
15
+ # merge parameters and values
16
+ type = "email"
17
+ method = "retrieve"
18
+ @parameters = {
19
+ "search_type" => "emailid",
20
+ "sub_action" => "htmlemail",
21
+ "search_value" => @email_id,
22
+ "search_value2" => "",
23
+ "search_value3" => "",
24
+ }
25
+
26
+ response = build_call(type, method)
27
+ response.xpath("//htmlbody").text rescue false
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,28 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def list_retrieve_subscribers(*args)
6
+
7
+ # options
8
+ options = args.extract_options!
9
+ @list_id = options[:list_id]
10
+
11
+ # check for required options
12
+ required_options = ["list_id"]
13
+ return false unless check_required(required_options)
14
+
15
+ # merge parameters and values
16
+ @parameters = {
17
+ "search_type" => "listid",
18
+ "search_value" => @list_id
19
+ }
20
+
21
+ response = build_call("list", "retrieve_sub", {:parse_response => false})
22
+ Hash.from_xml(response)['exacttarget']['system']['list']['subscribers'].first[1] rescue false
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,178 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def subscriber_add(*args)
6
+
7
+ # options
8
+ options = args.extract_options!
9
+ @list_id = options[:list_id] ||= nil
10
+ @email = options[:email]
11
+ @values = options[:values] ||= {}
12
+ @account_id = options[:account_id]
13
+
14
+ # check for required options
15
+ required_options = ["email", "list_id"]
16
+ return false unless check_required(required_options)
17
+
18
+ # update options
19
+ @values.merge!({"Email Address" => @email, "status" => "active"})
20
+
21
+ # merge parameters and values
22
+ @parameters = {
23
+ "search_type" => "listid",
24
+ "search_value" => @list_id,
25
+ "search_value2" => "",
26
+ "values" => @values
27
+ }
28
+
29
+ response = build_call("subscriber", "add")
30
+ response.xpath("//subscriber_description").text.to_i rescue false
31
+
32
+ end
33
+
34
+ def subscriber_edit(*args)
35
+
36
+ # options
37
+ options = args.extract_options!
38
+ @subscriber_id = options[:subscriber_id]
39
+ @values = options[:values] ||= {}
40
+ @account_id = options[:account_id] ||= ""
41
+
42
+ # check for required options
43
+ required_options = ["subscriber_id"]
44
+ return false unless check_required(required_options)
45
+
46
+ # merge parameters and values
47
+ @parameters = {
48
+ "search_type" => "subid",
49
+ "search_value" => @subscriber_id,
50
+ "search_value2" => "",
51
+ "values" => @values
52
+ }
53
+
54
+ response = build_call("subscriber", "edit")
55
+ response.xpath("//subscriber_description").text == @subscriber_id.to_s rescue false
56
+
57
+ end
58
+
59
+ def subscriber_edit_from_list(*args)
60
+
61
+ # options
62
+ options = args.extract_options!
63
+ @list_id = options[:list_id]
64
+ @email = options[:email]
65
+ @values = options[:values] ||= {}
66
+ @account_id = options[:account_id] ||= ""
67
+
68
+ # check for required options
69
+ required_options = ["list_id", "email"]
70
+ return false unless check_required(required_options)
71
+
72
+ # merge parameters and values
73
+ @parameters = {
74
+ "search_type" => "listid",
75
+ "search_value" => @list_id,
76
+ "search_value2" => @email,
77
+ "values" => @values
78
+ }
79
+
80
+ response = build_call("subscriber", "edit")
81
+ response.xpath("//subscriber_description").text.blank? && response.xpath("//subscriber_info").text.blank? ? false : true rescue false
82
+
83
+ end
84
+
85
+ def subscriber_delete(*args)
86
+
87
+ # options
88
+ options = args.extract_options!
89
+ @subscriber_id = options[:subscriber_id]
90
+
91
+ # check for required options
92
+ required_options = ["subscriber_id"]
93
+ return false unless check_required(required_options)
94
+
95
+ # merge parameters and values
96
+ @parameters = {
97
+ "search_type" => "subid",
98
+ "search_value" => @subscriber_id,
99
+ "search_value2" => ""
100
+ }
101
+
102
+ response = build_call("subscriber", "delete")
103
+ response.xpath("//subscriber_info").text.blank? ? false : true rescue false
104
+
105
+ end
106
+
107
+ def subscriber_remove_from_list(*args)
108
+
109
+ # options
110
+ options = args.extract_options!
111
+ @list_id = options[:list_id]
112
+ @email = options[:email]
113
+
114
+ # check for required options
115
+ required_options = ["list_id", "email"]
116
+ return false unless check_required(required_options)
117
+
118
+ # merge parameters and values
119
+ @parameters = {
120
+ "search_type" => "listid",
121
+ "search_value" => @list_id,
122
+ "search_value2" => @email
123
+ }
124
+
125
+ response = build_call("subscriber", "delete")
126
+ response.xpath("//subscriber_info").text.blank? ? false : true rescue false
127
+
128
+ end
129
+
130
+ def subscriber_unsubscribe_master(*args)
131
+
132
+ # options
133
+ options = args.extract_options!
134
+ @email = options[:email]
135
+
136
+ # check for required options
137
+ required_options = ["email"]
138
+ return false unless check_required(required_options)
139
+
140
+ # merge parameters and values
141
+ @parameters = {
142
+ "search_type" => "emailaddress",
143
+ "search_value" => {
144
+ "emailaddress" => @email
145
+ }
146
+ }
147
+
148
+ response = build_call("subscriber", "masterunsub")
149
+ response.xpath("//emailaddress").text == @email ? true : false rescue false
150
+
151
+ end
152
+
153
+ def subscriber_retrieve(*args)
154
+
155
+ # options
156
+ options = args.extract_options!
157
+ @subscriber_id = options[:subscriber_id]
158
+ @account_id = options[:account_id] ||= ""
159
+
160
+ # check for required options
161
+ required_options = ["subscriber_id"]
162
+ return false unless check_required(required_options)
163
+
164
+ # merge parameters and values
165
+ @parameters = {
166
+ "search_type" => "subid",
167
+ "search_value" => @subscriber_id,
168
+ "search_value2" => ""
169
+ }
170
+
171
+ response = build_call("subscriber", "retrieve", {:ignore_parse => true})
172
+ Hash.from_xml(response)['exacttarget']['system']['subscriber'].first rescue false
173
+
174
+ end
175
+
176
+ end
177
+
178
+ end
@@ -0,0 +1,32 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def tracking_retrieve(*args)
6
+
7
+ # options
8
+ options = args.extract_options!
9
+ @job_id = options[:job_id]
10
+
11
+ # check for required options
12
+ required_options = ["job_id"]
13
+ return false unless check_required(required_options)
14
+
15
+ # merge parameters and values
16
+ type = "tracking"
17
+ method = "retrieve"
18
+ @parameters = {
19
+ "search_type" => "jobID",
20
+ "sub_action" => "summary",
21
+ "search_value" => @job_id,
22
+ "search_value2" => ""
23
+ }
24
+
25
+ response = build_call(type, method, {:parse_response => false})
26
+ Hash.from_xml(response)['exacttarget']['system']['tracking']['emailSummary'] rescue false
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,49 @@
1
+ require("erb")
2
+ require("uri")
3
+ require("logger")
4
+ require("builder")
5
+ require("nokogiri")
6
+ require("net/https")
7
+ require("etapi/error")
8
+ require("etapi/exact_target")
9
+ require("etapi/call_builder")
10
+
11
+ include(ERB::Util)
12
+
13
+ module ETAPI
14
+ module Configuration
15
+
16
+ attr_accessor(
17
+ :username,
18
+ :password,
19
+ :use_s4,
20
+ :raise_errors,
21
+ :log
22
+ )
23
+
24
+ attr_writer(:log)
25
+ def log?
26
+ @log != false
27
+ end
28
+
29
+ def log(message)
30
+ logger.send(log_level, "\n#{message}\n") if log?
31
+ end
32
+
33
+ attr_writer(:logger)
34
+ def logger
35
+ @logger ||= ::Logger.new(STDOUT)
36
+ end
37
+
38
+ attr_writer(:log_level)
39
+ def log_level
40
+ @log_level ||= :debug
41
+ end
42
+
43
+ attr_writer(:raise_errors)
44
+ def raise_errors?
45
+ @raise_errors != false
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,46 @@
1
+ module ETAPI
2
+
3
+ class Session
4
+
5
+ def check_response(response)
6
+
7
+ raise Error.new(-1, 'Network error') if response.class != Net::HTTPOK
8
+
9
+ response = Nokogiri::XML::Document.parse(response.body)
10
+
11
+ error_code = response.xpath("//error")
12
+ error_msg = response.xpath("//error_description")
13
+
14
+ if !error_code.blank? && !error_msg.blank?
15
+ if ETAPI.raise_errors?
16
+ raise(RuntimeError, "\n\n Code: #{error_code.text.to_i}\n Message: #{error_msg.text}\n\n")
17
+ else
18
+ ETAPI.log(" Code: #{error_code.text.to_i}\n Message: #{error_msg.text}") if ETAPI.log?
19
+ return false
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ def check_required(required_options)
26
+ missing_options = []
27
+
28
+ for option in required_options
29
+ missing_options << ":#{option}" if eval("@#{option}.blank?")
30
+ end
31
+
32
+ if !missing_options.blank?
33
+ if ETAPI.log?
34
+ ETAPI.log(" Code: ETAPI\n Message: missing #{missing_options.join(', ')}")
35
+ elsif ETAPI.raise_errors?
36
+ raise(ArgumentError, "\n\n Code: ETAPI\n Message: missing #{missing_options.join(', ')}\n\n")
37
+ end
38
+ return false
39
+ end
40
+
41
+ return true
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,52 @@
1
+ require("etapi/calls/list")
2
+ require("etapi/calls/email")
3
+ require("etapi/calls/tracking")
4
+ require("etapi/calls/subscriber")
5
+
6
+ module ETAPI
7
+
8
+ class Session
9
+
10
+ # set default options
11
+ DEFAULTS = {
12
+ :api_method => :xml,
13
+ :use_s4 => false,
14
+ :api_uri_xml => "https://api.dc1.exacttarget.com/integrate.aspx",
15
+ :api_uri_xml_s4 => "https://api.s4.exacttarget.com/integrate.aspx",
16
+ :use_ssl => true,
17
+ }
18
+
19
+ # allowed options
20
+ ALLOWED_USE_S4_OPTIONS = [true, false]
21
+
22
+ # initialize a new exact target instance
23
+ def initialize(*args)
24
+
25
+ # merge options with configuration
26
+ options = args.extract_options!
27
+ @username = options[:username] ||= ETAPI.username
28
+ @password = options[:password] ||= ETAPI.password
29
+ @use_s4 = options[:use_s4] ||= ETAPI.use_s4 ||= DEFAULTS[:use_s4]
30
+ @headers = {"Content-Type" => "application/x-www-form-urlencoded", "Connection" => "close"}
31
+
32
+ # check for required options
33
+ raise ArgumentError, "* missing :username *" if @username.blank?
34
+ raise ArgumentError, "* missing :password *" if @password.blank?
35
+ raise ArgumentError, "* invalid :use_s4 | options => [true, false] *" unless ALLOWED_USE_S4_OPTIONS.include?(@use_s4)
36
+
37
+ @api_uri = @use_s4 ? DEFAULTS[:api_uri_xml_s4] : DEFAULTS[:api_uri_xml]
38
+
39
+ @api_wsdl = @api_uri if @use_s4
40
+
41
+ # parse uri
42
+ @api_uri = URI.parse(@api_uri)
43
+ @api_url = Net::HTTP.new(@api_uri.host, @api_uri.port)
44
+
45
+ # check for SSL (disabled)
46
+ @api_url.use_ssl = options[:use_ssl] ||= DEFAULTS[:use_ssl]
47
+
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,3 @@
1
+ module ETAPI
2
+ Version = "0.1.1"
3
+ end
data/lib/etapi.rb ADDED
@@ -0,0 +1,10 @@
1
+ require("etapi/configuration")
2
+
3
+ module ETAPI
4
+ extend Configuration
5
+
6
+ def self.configure
7
+ yield self if block_given?
8
+ end
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: etapi
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Chris McGrath
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-03 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: builder
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 15
29
+ segments:
30
+ - 2
31
+ - 1
32
+ - 2
33
+ version: 2.1.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: nokogiri
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 5
45
+ segments:
46
+ - 1
47
+ - 4
48
+ - 1
49
+ version: 1.4.1
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: This is an attempt to make integrating easier with Exact Target's XML APIs.
53
+ email:
54
+ - mcgrath.chris@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - etapi.gemspec
67
+ - lib/etapi.rb
68
+ - lib/etapi/call_builder.rb
69
+ - lib/etapi/calls/email.rb
70
+ - lib/etapi/calls/list.rb
71
+ - lib/etapi/calls/subscriber.rb
72
+ - lib/etapi/calls/tracking.rb
73
+ - lib/etapi/configuration.rb
74
+ - lib/etapi/error.rb
75
+ - lib/etapi/exact_target.rb
76
+ - lib/etapi/version.rb
77
+ homepage: http://github.com/phiction/etapi
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options: []
82
+
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ requirements: []
104
+
105
+ rubyforge_project: etapi
106
+ rubygems_version: 1.8.10
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Ruby Wrapper for Exact Target's APIs
110
+ test_files: []
111
+