exacttarget 0.1.2 → 0.1.3
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.
- data/Gemfile +3 -2
- data/Gemfile.lock +4 -2
- data/README.rdoc +2 -2
- data/Rakefile +9 -0
- data/VERSION +1 -1
- data/exacttarget.gemspec +17 -9
- data/lib/exacttarget.rb +148 -6
- data/lib/exacttarget/email.rb +152 -122
- data/lib/exacttarget/group.rb +76 -0
- data/lib/exacttarget/image.rb +33 -25
- data/lib/exacttarget/job.rb +58 -0
- data/lib/exacttarget/list.rb +109 -0
- data/lib/exacttarget/templates/group.xml.erb +7 -0
- data/lib/exacttarget/templates/image.xml.erb +1 -1
- data/lib/exacttarget/templates/job.xml.erb +31 -0
- data/lib/exacttarget/templates/list.xml.erb +11 -0
- data/lib/exacttarget/templates/main.xml.erb +2 -2
- metadata +32 -8
- data/lib/exacttarget/client.rb +0 -85
data/Gemfile
CHANGED
|
@@ -6,9 +6,10 @@ source "http://rubygems.org"
|
|
|
6
6
|
# Add dependencies to develop your gem here.
|
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
|
8
8
|
group :development do
|
|
9
|
-
gem "shoulda", ">=
|
|
9
|
+
gem "shoulda", ">= 2.11.3"
|
|
10
10
|
gem "bundler", "~> 1.0.0"
|
|
11
11
|
gem "jeweler", "~> 1.6.0"
|
|
12
|
-
gem "rcov", ">= 0"
|
|
12
|
+
gem "rcov", ">= 0.9.9"
|
|
13
13
|
gem "nokogiri", ">= 1.4.4"
|
|
14
|
+
gem "yard", ">= 0.6.8"
|
|
14
15
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -10,6 +10,7 @@ GEM
|
|
|
10
10
|
rake (0.8.7)
|
|
11
11
|
rcov (0.9.9)
|
|
12
12
|
shoulda (2.11.3)
|
|
13
|
+
yard (0.6.8)
|
|
13
14
|
|
|
14
15
|
PLATFORMS
|
|
15
16
|
ruby
|
|
@@ -18,5 +19,6 @@ DEPENDENCIES
|
|
|
18
19
|
bundler (~> 1.0.0)
|
|
19
20
|
jeweler (~> 1.6.0)
|
|
20
21
|
nokogiri (>= 1.4.4)
|
|
21
|
-
rcov
|
|
22
|
-
shoulda
|
|
22
|
+
rcov (>= 0.9.9)
|
|
23
|
+
shoulda (>= 2.11.3)
|
|
24
|
+
yard (>= 0.6.8)
|
data/README.rdoc
CHANGED
|
@@ -21,6 +21,6 @@ See LICENSE.txt for further details.
|
|
|
21
21
|
|
|
22
22
|
== Support
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
Provided through RubyDoc:
|
|
25
|
+
* http://rubydoc.info/github/msimpson/exacttarget/master/frames
|
|
26
26
|
|
data/Rakefile
CHANGED
|
@@ -41,3 +41,12 @@ Rake::RDocTask.new do |rdoc|
|
|
|
41
41
|
rdoc.rdoc_files.include('README*')
|
|
42
42
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
task :push do
|
|
46
|
+
system "yardoc"
|
|
47
|
+
system "git add ."
|
|
48
|
+
system "rake gemspec:generate"
|
|
49
|
+
system "git add ."
|
|
50
|
+
system "git commit -a"
|
|
51
|
+
system "rake git:release"
|
|
52
|
+
end
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.3
|
data/exacttarget.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{exacttarget}
|
|
8
|
-
s.version = "0.1.
|
|
8
|
+
s.version = "0.1.3"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Matthew Simpson"]
|
|
12
|
-
s.date = %q{2011-05-
|
|
12
|
+
s.date = %q{2011-05-15}
|
|
13
13
|
s.description = %q{ExactTarget is a client system for communicating with the ExactTarget email system. The client supports the most up-to-date XML API and is capable of uploading email pastes, images and retrieving lists of subscribers, emails and more.}
|
|
14
14
|
s.email = %q{matt.simpson@alextom.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -26,11 +26,16 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
"VERSION",
|
|
27
27
|
"exacttarget.gemspec",
|
|
28
28
|
"lib/exacttarget.rb",
|
|
29
|
-
"lib/exacttarget/client.rb",
|
|
30
29
|
"lib/exacttarget/email.rb",
|
|
30
|
+
"lib/exacttarget/group.rb",
|
|
31
31
|
"lib/exacttarget/image.rb",
|
|
32
|
+
"lib/exacttarget/job.rb",
|
|
33
|
+
"lib/exacttarget/list.rb",
|
|
32
34
|
"lib/exacttarget/templates/email.xml.erb",
|
|
35
|
+
"lib/exacttarget/templates/group.xml.erb",
|
|
33
36
|
"lib/exacttarget/templates/image.xml.erb",
|
|
37
|
+
"lib/exacttarget/templates/job.xml.erb",
|
|
38
|
+
"lib/exacttarget/templates/list.xml.erb",
|
|
34
39
|
"lib/exacttarget/templates/main.xml.erb"
|
|
35
40
|
]
|
|
36
41
|
s.homepage = %q{http://github.com/msimpson/exacttarget}
|
|
@@ -44,24 +49,27 @@ Gem::Specification.new do |s|
|
|
|
44
49
|
s.specification_version = 3
|
|
45
50
|
|
|
46
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
47
|
-
s.add_development_dependency(%q<shoulda>, [">=
|
|
52
|
+
s.add_development_dependency(%q<shoulda>, [">= 2.11.3"])
|
|
48
53
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
49
54
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
|
50
|
-
s.add_development_dependency(%q<rcov>, [">= 0"])
|
|
55
|
+
s.add_development_dependency(%q<rcov>, [">= 0.9.9"])
|
|
51
56
|
s.add_development_dependency(%q<nokogiri>, [">= 1.4.4"])
|
|
57
|
+
s.add_development_dependency(%q<yard>, [">= 0.6.8"])
|
|
52
58
|
else
|
|
53
|
-
s.add_dependency(%q<shoulda>, [">=
|
|
59
|
+
s.add_dependency(%q<shoulda>, [">= 2.11.3"])
|
|
54
60
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
55
61
|
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
|
56
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
|
62
|
+
s.add_dependency(%q<rcov>, [">= 0.9.9"])
|
|
57
63
|
s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
|
|
64
|
+
s.add_dependency(%q<yard>, [">= 0.6.8"])
|
|
58
65
|
end
|
|
59
66
|
else
|
|
60
|
-
s.add_dependency(%q<shoulda>, [">=
|
|
67
|
+
s.add_dependency(%q<shoulda>, [">= 2.11.3"])
|
|
61
68
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
62
69
|
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
|
63
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
|
70
|
+
s.add_dependency(%q<rcov>, [">= 0.9.9"])
|
|
64
71
|
s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
|
|
72
|
+
s.add_dependency(%q<yard>, [">= 0.6.8"])
|
|
65
73
|
end
|
|
66
74
|
end
|
|
67
75
|
|
data/lib/exacttarget.rb
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
# Nokogiri is required for XML parsing:
|
|
2
|
-
|
|
3
|
-
require 'nokogiri'
|
|
4
|
-
rescue LoadError
|
|
5
|
-
raise '[ExactTarget] Error: Nokogiri is missing, run "bundle install".'
|
|
6
|
-
end
|
|
2
|
+
require 'nokogiri'
|
|
7
3
|
|
|
8
4
|
# Standard:
|
|
9
5
|
require 'net/https'
|
|
@@ -12,5 +8,151 @@ require 'uri'
|
|
|
12
8
|
require 'erb'
|
|
13
9
|
|
|
14
10
|
# Library:
|
|
15
|
-
require 'exacttarget/
|
|
11
|
+
require 'exacttarget/job'
|
|
12
|
+
require 'exacttarget/list'
|
|
13
|
+
require 'exacttarget/group'
|
|
16
14
|
require 'exacttarget/email'
|
|
15
|
+
require 'exacttarget/image'
|
|
16
|
+
|
|
17
|
+
# ExactTarget XML API wrapper.
|
|
18
|
+
#
|
|
19
|
+
# @author Matthew Simpson (matt.simpson@alextom.com)
|
|
20
|
+
# @attr_reader [hash] :config Configuration hash
|
|
21
|
+
#
|
|
22
|
+
class ExactTarget
|
|
23
|
+
|
|
24
|
+
public
|
|
25
|
+
|
|
26
|
+
# Error/warning message header:
|
|
27
|
+
MSG = '[ExactTarget]'
|
|
28
|
+
# For error messages:
|
|
29
|
+
ERROR = "#{MSG} Error:"
|
|
30
|
+
# For warning messages:
|
|
31
|
+
WARN = "#{MSG} Warning:"
|
|
32
|
+
# The standard FTP name:
|
|
33
|
+
FTP_STANDARD_NAME = 'ExactTargetFTP'
|
|
34
|
+
# The standard FTP URI:
|
|
35
|
+
FTP_STANDARD_URI = 'ftp.exacttarget.com'
|
|
36
|
+
# The standard FTP path (directory):
|
|
37
|
+
FTP_STANDARD_PATH = '/'
|
|
38
|
+
# The enhanced FTP name:
|
|
39
|
+
FTP_ENHANCED_NAME = 'ExactTargetEnhancedFTP'
|
|
40
|
+
# The enhanced FTP URI:
|
|
41
|
+
FTP_ENHANCED_URI = 'ftp1.exacttarget.com'
|
|
42
|
+
# The enhanced FTP path (directory):
|
|
43
|
+
FTP_ENHANCED_PATH = '/import'
|
|
44
|
+
|
|
45
|
+
attr_reader :config
|
|
46
|
+
|
|
47
|
+
# Create a new ExactTarget API client.
|
|
48
|
+
#
|
|
49
|
+
# @example
|
|
50
|
+
# # Simple:
|
|
51
|
+
# client = ExactTarget.new :username => 'username', :password => 'password'
|
|
52
|
+
#
|
|
53
|
+
# # Using the enhanced FTP:
|
|
54
|
+
# client = ExactTarget.new(
|
|
55
|
+
# :username => 'username',
|
|
56
|
+
# :password => 'password',
|
|
57
|
+
# :ftp_username => '123456',
|
|
58
|
+
# :ftp_password => '123456',
|
|
59
|
+
# :ftp_name => ExactTarget::FTP_ENHANCED_NAME,
|
|
60
|
+
# :ftp_uri => ExactTarget::FTP_ENHANCED_URI,
|
|
61
|
+
# :ftp_path => ExactTarget::FTP_ENHANCED_PATH
|
|
62
|
+
# )
|
|
63
|
+
#
|
|
64
|
+
# @param [Hash] config Configuration hash (required)
|
|
65
|
+
# @option config [String] :username Username (required)
|
|
66
|
+
# @option config [String] :password Password (required)
|
|
67
|
+
# @option config [String] :api_uri ExactTarget API URI (needs to be the asp path)
|
|
68
|
+
# @option config [String] :ftp_username FTP username (default: import)
|
|
69
|
+
# @option config [String] :ftp_password FTP password (default: import)
|
|
70
|
+
# @option config [String] :ftp_name FTP name (default: ExactTargetFTP)
|
|
71
|
+
# @option config [String] :ftp_uri FTP URI (default: ftp.exacttarget.com)
|
|
72
|
+
# @option config [String] :ftp_path FTP path (defaults to root '/')
|
|
73
|
+
#
|
|
74
|
+
def initialize(config)
|
|
75
|
+
@config = {
|
|
76
|
+
:username => nil,
|
|
77
|
+
:password => nil,
|
|
78
|
+
:api_uri => 'https://api.dc1.exacttarget.com/integrate.asp',
|
|
79
|
+
:ftp_username => 'import',
|
|
80
|
+
:ftp_password => 'import',
|
|
81
|
+
:ftp_name => FTP_STANDARD_NAME,
|
|
82
|
+
:ftp_uri => FTP_STANDARD_URI,
|
|
83
|
+
:ftp_path => FTP_STANDARD_PATH
|
|
84
|
+
}.merge(config)
|
|
85
|
+
|
|
86
|
+
# Sanity check:
|
|
87
|
+
if @config[:username].nil? ||
|
|
88
|
+
@config[:password].nil?
|
|
89
|
+
raise "#{ERROR} username and password required!"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
ftp_connect
|
|
93
|
+
@uri = URI.parse(@config[:api_uri])
|
|
94
|
+
@api = Net::HTTP.new(@uri.host, @uri.port)
|
|
95
|
+
@api.use_ssl = true
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def ftp_connect
|
|
101
|
+
begin
|
|
102
|
+
@ftp = Net::FTP.new(@config[:ftp_uri])
|
|
103
|
+
@ftp.login @config[:ftp_username], @config[:ftp_password]
|
|
104
|
+
@ftp.chdir @config[:ftp_path]
|
|
105
|
+
rescue => msg
|
|
106
|
+
puts "#{ERROR} FTP access failed!"
|
|
107
|
+
raise msg
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def ftp_put(file_path)
|
|
112
|
+
ftp_connect if @ftp.closed?
|
|
113
|
+
|
|
114
|
+
begin
|
|
115
|
+
@ftp.noop
|
|
116
|
+
@ftp.put(file_path.to_s)
|
|
117
|
+
rescue => msg
|
|
118
|
+
puts "#{ERROR} FTP put failed!"
|
|
119
|
+
raise msg
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def ftp_delete(file_name)
|
|
124
|
+
ftp_connect if @ftp.closed?
|
|
125
|
+
|
|
126
|
+
begin
|
|
127
|
+
@ftp.noop
|
|
128
|
+
@ftp.delete(file_name.to_s)
|
|
129
|
+
rescue => msg
|
|
130
|
+
puts "#{ERROR} FTP delete failed!"
|
|
131
|
+
raise msg
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def render(template)
|
|
136
|
+
path = File.join(File.dirname(__FILE__), "exacttarget/templates/#{template.to_s}.xml.erb")
|
|
137
|
+
file = File.open(path, 'r').read
|
|
138
|
+
ERB.new(file, 0, '<>').result(binding)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def send(xml)
|
|
142
|
+
@system = xml
|
|
143
|
+
post = 'qf=xml&xml=' + URI.escape(render(:main))
|
|
144
|
+
|
|
145
|
+
begin
|
|
146
|
+
@api.post(@uri.path, post,
|
|
147
|
+
{
|
|
148
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
149
|
+
'Content-length' => post.length.to_s
|
|
150
|
+
}
|
|
151
|
+
).body
|
|
152
|
+
rescue => msg
|
|
153
|
+
puts "#{ERROR} API request failed."
|
|
154
|
+
raise msg
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
end
|
data/lib/exacttarget/email.rb
CHANGED
|
@@ -1,135 +1,165 @@
|
|
|
1
|
-
|
|
2
|
-
class Client
|
|
1
|
+
class ExactTarget
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
public
|
|
4
|
+
|
|
5
|
+
# Find all emails.
|
|
6
|
+
#
|
|
7
|
+
# @param [bool] body Retrieve HTML body of each email (can cause seriously lag) [dangerous]
|
|
8
|
+
#
|
|
9
|
+
def email_find_all(body = false)
|
|
10
|
+
email_find({ :body => body })
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Retrieve an email by its ID.
|
|
14
|
+
#
|
|
15
|
+
# @param [int,string] id Email ID
|
|
16
|
+
# @param [hash] options Other options
|
|
17
|
+
# @see ExactTarget#email_find
|
|
18
|
+
#
|
|
19
|
+
def email_find_by_id(id, options = {})
|
|
20
|
+
email_find({
|
|
21
|
+
:id => id,
|
|
22
|
+
:body => true
|
|
23
|
+
}.merge(options))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Find all emails who's name includes the given keyword.
|
|
27
|
+
#
|
|
28
|
+
# @param [string] name Name of the email (keyword)
|
|
29
|
+
# @param [hash] options Other options
|
|
30
|
+
# @see ExactTarget#email_find
|
|
31
|
+
#
|
|
32
|
+
def email_find_by_name(name, options = {})
|
|
33
|
+
email_find({
|
|
34
|
+
:name => name,
|
|
35
|
+
}.merge(options))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Find all emails who's subject includes the given keyword.
|
|
39
|
+
#
|
|
40
|
+
# @param [string] subject Subject of the email (keyword)
|
|
41
|
+
# @param [hash] options Other options
|
|
42
|
+
# @see ExactTarget#email_find
|
|
43
|
+
#
|
|
44
|
+
def email_find_by_subject(subject, options = {})
|
|
45
|
+
email_find({
|
|
46
|
+
:subject => subject,
|
|
47
|
+
}.merge(options))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Find all emails who's attributes match the selected options.
|
|
51
|
+
#
|
|
52
|
+
# @param [hash] options Options hash
|
|
53
|
+
# @option options [int,string] :id Email ID
|
|
54
|
+
# @option options [string] :name Name of the email (keyword search)
|
|
55
|
+
# @option options [string] :subject Subject of the email (keyword search)
|
|
56
|
+
# @option options [date] :start The date at which to start the search
|
|
57
|
+
# @option options [date] :end The date at which to end the search
|
|
58
|
+
# @option options [bool] :body Whether or not to retrieve the HTML body of the email
|
|
59
|
+
#
|
|
60
|
+
def email_find(options = {})
|
|
61
|
+
@action = 'retrieve'
|
|
62
|
+
@sub_action = 'all'
|
|
63
|
+
@type = ''
|
|
64
|
+
@value = ''
|
|
22
65
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
end
|
|
66
|
+
id = options[:id] || false
|
|
67
|
+
name = options[:name] || false
|
|
68
|
+
subject = options[:subject] || false
|
|
69
|
+
start_date = options[:start] || false
|
|
70
|
+
end_date = options[:end] || false
|
|
71
|
+
get_body = options[:body] || false
|
|
72
|
+
list = []
|
|
28
73
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.exacttarget
|
|
54
|
-
.system
|
|
55
|
-
.email
|
|
56
|
-
.emaillist.each do |email|
|
|
57
|
-
(next if email.emailid.content != id.to_s) if id
|
|
58
|
-
(next if !email.emailname.content.include? name.to_s) if name
|
|
59
|
-
(next if !email.emailsubject.content.include? subject.to_s) if subject
|
|
60
|
-
|
|
61
|
-
date = format.call(email.emailcreateddate.content)
|
|
74
|
+
Nokogiri::Slop(send(render(:email)))
|
|
75
|
+
.exacttarget
|
|
76
|
+
.system
|
|
77
|
+
.email
|
|
78
|
+
.emaillist.each do |email|
|
|
79
|
+
(next if email.emailid.content != id.to_s) if id
|
|
80
|
+
(next if !email.emailname.content.include? name.to_s) if name
|
|
81
|
+
(next if !email.emailsubject.content.include? subject.to_s) if subject
|
|
82
|
+
|
|
83
|
+
date = Date.strptime(email.emailcreateddate.content, '%m/%d/%Y')
|
|
84
|
+
|
|
85
|
+
(next if date < start_date) if start_date && start_date.instance_of?(Date)
|
|
86
|
+
(next if date > end_date) if end_date && end_date.instance_of?(Date)
|
|
87
|
+
|
|
88
|
+
body = email_get_body(email.emailid.content) if get_body
|
|
89
|
+
|
|
90
|
+
email.instance_eval do
|
|
91
|
+
new = {
|
|
92
|
+
:id => emailid.content,
|
|
93
|
+
:name => emailname.content,
|
|
94
|
+
:subject => emailsubject.content,
|
|
95
|
+
:date => date,
|
|
96
|
+
:category_id => categoryid.content
|
|
97
|
+
}
|
|
62
98
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
body = email_get_body(email.emailid.content) if get_body
|
|
67
|
-
|
|
68
|
-
email.instance_eval do
|
|
69
|
-
new = {
|
|
70
|
-
:id => emailid.content,
|
|
71
|
-
:name => emailname.content,
|
|
72
|
-
:subject => emailsubject.content,
|
|
73
|
-
:date => email.emailcreateddate.content,
|
|
74
|
-
:category_id => categoryid.content
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
new[:body] = body if get_body
|
|
78
|
-
list << new
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
list
|
|
99
|
+
new[:body] = body if get_body
|
|
100
|
+
list << new
|
|
101
|
+
end
|
|
83
102
|
end
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
list
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Create an email.
|
|
108
|
+
#
|
|
109
|
+
# @param [string] name Name of the new email
|
|
110
|
+
# @param [string] subject The subject line
|
|
111
|
+
# @param [string] html The HTML source
|
|
112
|
+
# @param [string] text The text version
|
|
113
|
+
#
|
|
114
|
+
# @see ExactTarget#job_send #email_send (job_send) for sending emails.
|
|
115
|
+
#
|
|
116
|
+
def email_create(name, subject, html, text = false)
|
|
117
|
+
id = email_add_html(name, subject, html)
|
|
118
|
+
email_add_text(id, text) if text
|
|
119
|
+
id
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def email_add_html(name, subject, html)
|
|
125
|
+
@action = 'add'
|
|
126
|
+
@sub_action = 'HTMLPaste'
|
|
127
|
+
@name = name.to_s
|
|
128
|
+
@subject = subject.to_s
|
|
129
|
+
@body = html
|
|
90
130
|
|
|
91
|
-
|
|
131
|
+
result = Nokogiri::XML(send(render(:email)))
|
|
132
|
+
id = result.xpath('//emailID').text
|
|
92
133
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
raise '[ExactTarget] Error: Email HTMLPaste failed.' if id.empty?
|
|
104
|
-
id
|
|
105
|
-
end
|
|
134
|
+
raise "#{ERROR} email HTMLPaste failed." if id.empty?
|
|
135
|
+
id
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def email_add_text(id, text)
|
|
139
|
+
@action = 'add'
|
|
140
|
+
@sub_action = 'text'
|
|
141
|
+
@id = id
|
|
142
|
+
@body = text
|
|
106
143
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@sub_action = 'text'
|
|
110
|
-
@id = id
|
|
111
|
-
@body = text
|
|
112
|
-
|
|
113
|
-
result = Nokogiri::XML(send(render(:email)))
|
|
114
|
-
info = result.xpath('//email_info').text
|
|
115
|
-
|
|
116
|
-
raise '[ExactTarget] Error: Email text update failed.' if info.empty?
|
|
117
|
-
true
|
|
118
|
-
end
|
|
144
|
+
result = Nokogiri::XML(send(render(:email)))
|
|
145
|
+
info = result.xpath('//email_info').text
|
|
119
146
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
rescue
|
|
130
|
-
nil
|
|
131
|
-
end
|
|
132
|
-
end
|
|
147
|
+
raise "#{ERROR} email text update failed." if info.empty?
|
|
148
|
+
true
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def email_get_body(id)
|
|
152
|
+
@action = 'retrieve'
|
|
153
|
+
@sub_action = 'htmlemail'
|
|
154
|
+
@type = 'emailid'
|
|
155
|
+
@value = id.to_s
|
|
133
156
|
|
|
157
|
+
begin
|
|
158
|
+
Nokogiri::XML(send(render(:email)))
|
|
159
|
+
.xpath('//htmlbody').text
|
|
160
|
+
rescue
|
|
161
|
+
nil
|
|
162
|
+
end
|
|
134
163
|
end
|
|
164
|
+
|
|
135
165
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
class ExactTarget
|
|
2
|
+
|
|
3
|
+
public
|
|
4
|
+
|
|
5
|
+
# Retrieve a group by its ID.
|
|
6
|
+
#
|
|
7
|
+
# @param [int,string] id Group ID
|
|
8
|
+
# @param [hash] options Other options
|
|
9
|
+
# @see ExactTarget#group_find
|
|
10
|
+
#
|
|
11
|
+
def group_find_by_id(id, options = {})
|
|
12
|
+
group_find({
|
|
13
|
+
:id => id
|
|
14
|
+
}.merge(options))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Retrieve a group by its name.
|
|
18
|
+
#
|
|
19
|
+
# @param [string] name Group name
|
|
20
|
+
# @param [hash] options Other options
|
|
21
|
+
# @see ExactTarget#group_find
|
|
22
|
+
#
|
|
23
|
+
def group_find_by_name(name, options = {})
|
|
24
|
+
group_find({
|
|
25
|
+
:name => name
|
|
26
|
+
}.merge(options))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Retrieve a group by its description.
|
|
30
|
+
#
|
|
31
|
+
# @param [string] desc Group description
|
|
32
|
+
# @param [hash] options Other options
|
|
33
|
+
# @see ExactTarget#group_find
|
|
34
|
+
#
|
|
35
|
+
def group_find_by_desc(desc, options = {})
|
|
36
|
+
group_find({
|
|
37
|
+
:desc => desc
|
|
38
|
+
}.merge(options))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Find all groups who's attributes match the selected options.
|
|
42
|
+
#
|
|
43
|
+
# @param [hash] options Options hash
|
|
44
|
+
# @option options [int,string] :id Group ID
|
|
45
|
+
# @option options [string] :name Name of the group (keyword search)
|
|
46
|
+
# @option options [string] :desc Description of the group (keyword search)
|
|
47
|
+
#
|
|
48
|
+
def group_find(options = {})
|
|
49
|
+
id = options[:id] || false
|
|
50
|
+
name = options[:name] || false
|
|
51
|
+
desc = options[:desc] || false
|
|
52
|
+
groups = []
|
|
53
|
+
|
|
54
|
+
Nokogiri::Slop(send(render(:group)))
|
|
55
|
+
.exacttarget
|
|
56
|
+
.system
|
|
57
|
+
.list
|
|
58
|
+
.groups.each do |group|
|
|
59
|
+
(next if group.groupID.content != id.to_s) if id
|
|
60
|
+
(next if !group.groupName.content.include? name.to_s) if name
|
|
61
|
+
(next if !group.description.content.include? desc.to_s) if desc
|
|
62
|
+
|
|
63
|
+
group.instance_eval do
|
|
64
|
+
groups << {
|
|
65
|
+
:id => groupID.content,
|
|
66
|
+
:name => groupName.content,
|
|
67
|
+
:desc => description.content
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
groups
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
alias :group_find_all :group_find
|
|
75
|
+
|
|
76
|
+
end
|
data/lib/exacttarget/image.rb
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
class Client
|
|
1
|
+
class ExactTarget
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
public
|
|
4
|
+
|
|
5
|
+
# Upload an image (note: uses the FTP and cleans up afterward).
|
|
6
|
+
#
|
|
7
|
+
# @param [string] file_path The file path of the image to upload/import
|
|
8
|
+
#
|
|
9
|
+
def image_import(file_path)
|
|
10
|
+
@name = File.basename(file_path)
|
|
11
|
+
|
|
12
|
+
ftp_put(file_path.to_s)
|
|
13
|
+
|
|
14
|
+
result = Nokogiri::XML(send(render(:image)))
|
|
15
|
+
desc = result.xpath('//filemanagement-description').text
|
|
16
|
+
total = result.xpath('//filemanagement-totalmoved').text.to_i
|
|
17
|
+
name = result.xpath('//filemanagement-info').text
|
|
18
|
+
error = desc.include?('not exist') ? 'File not found' : total < 1 ? 'Unsupported file type' : nil
|
|
5
19
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
desc = result.xpath('//filemanagement-description').text
|
|
18
|
-
total = result.xpath('//filemanagement-totalmoved').text.to_i
|
|
19
|
-
name = result.xpath('//filemanagement-info').text
|
|
20
|
-
error = desc.include?('not exist') ? 'File not found.' : total < 1 ? 'Unsupported file type.' : nil
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
:file_path => file_path,
|
|
24
|
-
:old_name => @name,
|
|
25
|
-
:new_name => name,
|
|
26
|
-
:error => error
|
|
27
|
-
}
|
|
20
|
+
count = 0
|
|
21
|
+
limit = 15
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
sleep 0.5
|
|
25
|
+
ftp_delete(@name)
|
|
26
|
+
rescue
|
|
27
|
+
count += 1
|
|
28
|
+
retry if count < limit
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
{
|
|
32
|
+
:file_path => file_path.to_s,
|
|
33
|
+
:old_name => @name,
|
|
34
|
+
:new_name => name,
|
|
35
|
+
:error => error
|
|
36
|
+
}
|
|
30
37
|
end
|
|
38
|
+
|
|
31
39
|
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
class ExactTarget
|
|
2
|
+
|
|
3
|
+
public
|
|
4
|
+
|
|
5
|
+
# Send an email to a collection of lists or groups.
|
|
6
|
+
#
|
|
7
|
+
# @param [hash] options Options hash
|
|
8
|
+
# @option options [int,string] :id Email ID
|
|
9
|
+
# @option options [array] :include The collection of lists or groups to target
|
|
10
|
+
# @option options [array] :exclude The collection of lists or groups to skip
|
|
11
|
+
# @option options [string] :from_name Name of sender (only if supported by your account)
|
|
12
|
+
# @option options [string] :from_email Email address of sender (only if supported by your account)
|
|
13
|
+
# @option options [string] :additional Additional information to include
|
|
14
|
+
# @option options [date,datetime] :when The date and/or time which to send the email(s)
|
|
15
|
+
# @option options [bool] :multipart Whether or not to send in multiple parts (for MIME compatibility)
|
|
16
|
+
# @option options [bool] :track Whether or not to track hyperlink clicks
|
|
17
|
+
# @option options [bool] :test If true, suppress email(s) from Performance Reports
|
|
18
|
+
#
|
|
19
|
+
def job_send(options)
|
|
20
|
+
@options = {
|
|
21
|
+
:id => nil,
|
|
22
|
+
:include => [],
|
|
23
|
+
:exclude => [],
|
|
24
|
+
:from_name => nil,
|
|
25
|
+
:from_email => nil,
|
|
26
|
+
:additional => nil,
|
|
27
|
+
:when => nil,
|
|
28
|
+
:multipart => false,
|
|
29
|
+
:track => true,
|
|
30
|
+
:test => false
|
|
31
|
+
}.merge(options)
|
|
32
|
+
|
|
33
|
+
# Sanity check:
|
|
34
|
+
if @options[:id].nil? ||
|
|
35
|
+
@options[:include].empty?
|
|
36
|
+
raise "#{ERROR} id and include array/string required!"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@date =
|
|
40
|
+
(@options[:when].strftime('%-m/%-d/%Y') if
|
|
41
|
+
@options[:when].instance_of?(Date) ||
|
|
42
|
+
@options[:when].instance_of?(DateTime)) || 'immediate'
|
|
43
|
+
|
|
44
|
+
@time =
|
|
45
|
+
(@options[:when].strftime('%H:%M') if
|
|
46
|
+
@options[:when].instance_of?(DateTime)) || ''
|
|
47
|
+
|
|
48
|
+
result = Nokogiri::XML(send(render(:job)))
|
|
49
|
+
info = result.xpath('//job_info').text
|
|
50
|
+
desc = result.xpath('//job_description').text
|
|
51
|
+
|
|
52
|
+
raise "#{ERROR} job send failed !" if !info.include? 'success'
|
|
53
|
+
desc
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
alias :email_send :job_send
|
|
57
|
+
|
|
58
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
class ExactTarget
|
|
2
|
+
|
|
3
|
+
public
|
|
4
|
+
|
|
5
|
+
# Retrieve a list by its ID.
|
|
6
|
+
#
|
|
7
|
+
# @param [int,string] id List ID
|
|
8
|
+
# @param [hash] options Other options
|
|
9
|
+
# @see ExactTarget#list_find
|
|
10
|
+
#
|
|
11
|
+
def list_find_by_id(id, options = {})
|
|
12
|
+
list_find({
|
|
13
|
+
:id => id
|
|
14
|
+
}.merge(options))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Find all lists who's name includes the given keyword.
|
|
18
|
+
#
|
|
19
|
+
# @param [string] name Name of the list (keyword)
|
|
20
|
+
# @param [hash] options Other options
|
|
21
|
+
# @see ExactTarget#list_find
|
|
22
|
+
#
|
|
23
|
+
def list_find_by_name(name, options = {})
|
|
24
|
+
list_find({
|
|
25
|
+
:name => name,
|
|
26
|
+
}.merge(options))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Find all lists who's type includes the given keyword.
|
|
30
|
+
#
|
|
31
|
+
# @param [string] subject Type of the list (keyword)
|
|
32
|
+
# @param [hash] options Other options
|
|
33
|
+
# @see ExactTarget#list_find
|
|
34
|
+
#
|
|
35
|
+
def list_find_by_type(type, options = {})
|
|
36
|
+
list_find({
|
|
37
|
+
:type => subject,
|
|
38
|
+
}.merge(options))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Find all lists who's attributes match the selected options.
|
|
42
|
+
#
|
|
43
|
+
# @param [hash] options Options hash
|
|
44
|
+
# @option options [int,string] :id list ID
|
|
45
|
+
# @option options [string] :name Name of the list (keyword search)
|
|
46
|
+
# @option options [string] :type Type of the list (keyword search)
|
|
47
|
+
# @option options [date] :start The date at which to start the search
|
|
48
|
+
# @option options [date] :end The date at which to end the search
|
|
49
|
+
#
|
|
50
|
+
def list_find(options = {})
|
|
51
|
+
id = options[:id] || false
|
|
52
|
+
name = options[:name] || false
|
|
53
|
+
type = options[:type] || false
|
|
54
|
+
start_date = options[:start] || false
|
|
55
|
+
end_date = options[:end] || false
|
|
56
|
+
list = list_get_all
|
|
57
|
+
|
|
58
|
+
list.select do |item|
|
|
59
|
+
(next if item[:id] != id.to_s) if id
|
|
60
|
+
(next if !item[:name].include? name.to_s) if name
|
|
61
|
+
(next if !item[:type].include? type.to_s) if type
|
|
62
|
+
(next if item[:modified] < start_date) if start_date && start_date.instance_of?(DateTime)
|
|
63
|
+
(next if item[:modified] > end_date) if end_date && end_date.instance_of?(DateTime)
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
alias :list_find_all :list_find
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def list_get_all
|
|
73
|
+
@action = 'retrieve'
|
|
74
|
+
@type = 'listname'
|
|
75
|
+
@value = ''
|
|
76
|
+
|
|
77
|
+
result = Nokogiri::XML(send(render(:list)))
|
|
78
|
+
error = result.xpath('//error_description').text
|
|
79
|
+
id_list = result.xpath('//listid').map &:text
|
|
80
|
+
list = []
|
|
81
|
+
|
|
82
|
+
id_list.each { |id| list << list_get_details(id) } if error.empty?
|
|
83
|
+
list
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def list_get_details(id)
|
|
87
|
+
@action = 'retrieve'
|
|
88
|
+
@type = 'listid'
|
|
89
|
+
@value = id.to_s
|
|
90
|
+
|
|
91
|
+
result = Nokogiri::XML(send(render(:list)))
|
|
92
|
+
error = result.xpath('//error_description').text
|
|
93
|
+
error = error.empty? ? nil : error
|
|
94
|
+
|
|
95
|
+
{
|
|
96
|
+
:id => id.to_s,
|
|
97
|
+
:name => result.xpath('//list_name').text,
|
|
98
|
+
:type => result.xpath('//list_type').text,
|
|
99
|
+
:modified => (DateTime.strptime(result.xpath('//modified').text, '%m/%d/%Y %I:%M:%S %p') if !error),
|
|
100
|
+
:total => (result.xpath('//subscriber_count').text.to_i if !error),
|
|
101
|
+
:subscribed => (result.xpath('//active_total').text.to_i if !error),
|
|
102
|
+
:unsubscribed => (result.xpath('//unsub_count').text.to_i if !error),
|
|
103
|
+
:bounce => (result.xpath('//bounce_count').text.to_i if !error),
|
|
104
|
+
:held => (result.xpath('//held_count').text.to_i if !error),
|
|
105
|
+
:error => error
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<system>
|
|
2
|
+
|
|
3
|
+
<system_name>job</system_name>
|
|
4
|
+
<action>send</action>
|
|
5
|
+
<search_type>emailid</search_type>
|
|
6
|
+
<search_value><%= @options[:id].to_s %></search_value>
|
|
7
|
+
|
|
8
|
+
<from_name><%= @options[:from_name].to_s %></from_name>
|
|
9
|
+
<from_email><%= @options[:from_email].to_s %></from_email>
|
|
10
|
+
<additional><%= @options[:additional].to_s %></additional>
|
|
11
|
+
<multipart_mime><%= @options[:multipart].to_s %></multipart_mime>
|
|
12
|
+
<track_links><%= @options[:track].to_s %></track_links>
|
|
13
|
+
|
|
14
|
+
<send_date><%= @date %></send_date>
|
|
15
|
+
<send_time><%= @time %></send_time>
|
|
16
|
+
|
|
17
|
+
<lists>
|
|
18
|
+
<% @options[:include].each do |id| %>
|
|
19
|
+
<list><%= id %></list>
|
|
20
|
+
<% end %>
|
|
21
|
+
</lists>
|
|
22
|
+
|
|
23
|
+
<suppress>
|
|
24
|
+
<% @options[:exclude].each do |id| %>
|
|
25
|
+
<list><%= id %></list>
|
|
26
|
+
<% end %>
|
|
27
|
+
</suppress>
|
|
28
|
+
|
|
29
|
+
<test_send><%= @options[:test].to_s %></test_send>
|
|
30
|
+
|
|
31
|
+
</system>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<?xml version="1.0" ?>
|
|
2
2
|
<exacttarget>
|
|
3
3
|
<authorization>
|
|
4
|
-
<username><%= @username %></username>
|
|
5
|
-
<password><%= @password %></password>
|
|
4
|
+
<username><%= @config[:username] %></username>
|
|
5
|
+
<password><%= @config[:password] %></password>
|
|
6
6
|
</authorization>
|
|
7
7
|
<%= @system %>
|
|
8
8
|
</exacttarget>
|
metadata
CHANGED
|
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
|
5
5
|
segments:
|
|
6
6
|
- 0
|
|
7
7
|
- 1
|
|
8
|
-
-
|
|
9
|
-
version: 0.1.
|
|
8
|
+
- 3
|
|
9
|
+
version: 0.1.3
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Matthew Simpson
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2011-05-
|
|
17
|
+
date: 2011-05-15 00:00:00 -04:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
@@ -25,8 +25,10 @@ dependencies:
|
|
|
25
25
|
- - ">="
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
27
|
segments:
|
|
28
|
-
-
|
|
29
|
-
|
|
28
|
+
- 2
|
|
29
|
+
- 11
|
|
30
|
+
- 3
|
|
31
|
+
version: 2.11.3
|
|
30
32
|
type: :development
|
|
31
33
|
prerelease: false
|
|
32
34
|
version_requirements: *id001
|
|
@@ -69,7 +71,9 @@ dependencies:
|
|
|
69
71
|
- !ruby/object:Gem::Version
|
|
70
72
|
segments:
|
|
71
73
|
- 0
|
|
72
|
-
|
|
74
|
+
- 9
|
|
75
|
+
- 9
|
|
76
|
+
version: 0.9.9
|
|
73
77
|
type: :development
|
|
74
78
|
prerelease: false
|
|
75
79
|
version_requirements: *id004
|
|
@@ -88,6 +92,21 @@ dependencies:
|
|
|
88
92
|
type: :development
|
|
89
93
|
prerelease: false
|
|
90
94
|
version_requirements: *id005
|
|
95
|
+
- !ruby/object:Gem::Dependency
|
|
96
|
+
name: yard
|
|
97
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
|
98
|
+
none: false
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
segments:
|
|
103
|
+
- 0
|
|
104
|
+
- 6
|
|
105
|
+
- 8
|
|
106
|
+
version: 0.6.8
|
|
107
|
+
type: :development
|
|
108
|
+
prerelease: false
|
|
109
|
+
version_requirements: *id006
|
|
91
110
|
description: ExactTarget is a client system for communicating with the ExactTarget email system. The client supports the most up-to-date XML API and is capable of uploading email pastes, images and retrieving lists of subscribers, emails and more.
|
|
92
111
|
email: matt.simpson@alextom.com
|
|
93
112
|
executables: []
|
|
@@ -107,11 +126,16 @@ files:
|
|
|
107
126
|
- VERSION
|
|
108
127
|
- exacttarget.gemspec
|
|
109
128
|
- lib/exacttarget.rb
|
|
110
|
-
- lib/exacttarget/client.rb
|
|
111
129
|
- lib/exacttarget/email.rb
|
|
130
|
+
- lib/exacttarget/group.rb
|
|
112
131
|
- lib/exacttarget/image.rb
|
|
132
|
+
- lib/exacttarget/job.rb
|
|
133
|
+
- lib/exacttarget/list.rb
|
|
113
134
|
- lib/exacttarget/templates/email.xml.erb
|
|
135
|
+
- lib/exacttarget/templates/group.xml.erb
|
|
114
136
|
- lib/exacttarget/templates/image.xml.erb
|
|
137
|
+
- lib/exacttarget/templates/job.xml.erb
|
|
138
|
+
- lib/exacttarget/templates/list.xml.erb
|
|
115
139
|
- lib/exacttarget/templates/main.xml.erb
|
|
116
140
|
has_rdoc: true
|
|
117
141
|
homepage: http://github.com/msimpson/exacttarget
|
|
@@ -127,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
127
151
|
requirements:
|
|
128
152
|
- - ">="
|
|
129
153
|
- !ruby/object:Gem::Version
|
|
130
|
-
hash:
|
|
154
|
+
hash: 1094960179515826332
|
|
131
155
|
segments:
|
|
132
156
|
- 0
|
|
133
157
|
version: "0"
|
data/lib/exacttarget/client.rb
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
module ExactTarget
|
|
2
|
-
FTP_STANDARD = {
|
|
3
|
-
:location => 'ExactTargetFTP',
|
|
4
|
-
:uri => 'ftp.exacttarget.com',
|
|
5
|
-
:path => '/',
|
|
6
|
-
}
|
|
7
|
-
FTP_ENHANCED = {
|
|
8
|
-
:location => 'ExactTargetEnhancedFTP',
|
|
9
|
-
:uri => 'ftp1.exacttarget.com',
|
|
10
|
-
:path => '/import',
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
class Client
|
|
14
|
-
|
|
15
|
-
attr_reader :username, :password, :ftp
|
|
16
|
-
|
|
17
|
-
public
|
|
18
|
-
|
|
19
|
-
def initialize(username, password, ftp_username = 'import', ftp_password = 'import', ftp = FTP_STANDARD)
|
|
20
|
-
@username = username
|
|
21
|
-
@password = password
|
|
22
|
-
@ftp = {
|
|
23
|
-
:username => ftp_username.to_s,
|
|
24
|
-
:password => ftp_password.to_s,
|
|
25
|
-
:handle => Net::FTP.new(ftp[:uri])
|
|
26
|
-
}.merge ftp
|
|
27
|
-
|
|
28
|
-
begin
|
|
29
|
-
@ftp[:handle].login @ftp[:username], @ftp[:password]
|
|
30
|
-
@ftp[:handle].chdir @ftp[:path]
|
|
31
|
-
rescue Net::FTPPermError => msg
|
|
32
|
-
puts '[ExactTarget] Error: FTP access failed.'
|
|
33
|
-
raise msg
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
@uri = URI.parse('https://api.dc1.exacttarget.com/integrate.asp')
|
|
37
|
-
@api = Net::HTTP.new(@uri.host, @uri.port)
|
|
38
|
-
@api.use_ssl = true
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def put(file_path)
|
|
44
|
-
begin
|
|
45
|
-
@ftp[:handle].put(file_path.to_s)
|
|
46
|
-
rescue Exception => msg
|
|
47
|
-
puts '[ExactTarget] Error: FTP put failed.'
|
|
48
|
-
raise msg
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def delete(file_name)
|
|
53
|
-
begin
|
|
54
|
-
@ftp[:handle].delete(file_name.to_s)
|
|
55
|
-
rescue Exception => msg
|
|
56
|
-
puts '[ExactTarget] Error: FTP delete failed.'
|
|
57
|
-
raise msg
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def render(template)
|
|
62
|
-
path = File.join(File.dirname(__FILE__), "templates/#{template.to_s}.xml.erb")
|
|
63
|
-
file = File.open(path, 'r').read
|
|
64
|
-
ERB.new(file, 0, '<>').result(binding)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def send(xml)
|
|
68
|
-
@system = xml
|
|
69
|
-
post = 'qf=xml&xml=' + URI.escape(render(:main))
|
|
70
|
-
|
|
71
|
-
begin
|
|
72
|
-
@api.post(@uri.path, post,
|
|
73
|
-
{
|
|
74
|
-
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
75
|
-
'Content-length' => post.length.to_s
|
|
76
|
-
}
|
|
77
|
-
).body
|
|
78
|
-
rescue SocketError => msg
|
|
79
|
-
puts '[ExactTarget] Error: API request failed.'
|
|
80
|
-
raise msg
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
end
|
|
85
|
-
end
|