exact-target 0.0.4

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.
@@ -0,0 +1,22 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ README.rdoc
4
+ Rakefile
5
+ lib/exact_target.rb
6
+ lib/exact_target/builder_ext.rb
7
+ lib/exact_target/configuration.rb
8
+ lib/exact_target/error.rb
9
+ lib/exact_target/net_https_hack.rb
10
+ lib/exact_target/request_builder.rb
11
+ lib/exact_target/response_class.erb
12
+ lib/exact_target/response_classes.rb
13
+ lib/exact_target/response_handler.rb
14
+ lib/exact_target/string_ext.rb
15
+ spec/exact_target/net_https_hack_spec.rb
16
+ spec/exact_target/response_handler_spec.rb
17
+ spec/exact_target/string_ext_spec.rb
18
+ spec/exact_target_data.yml
19
+ spec/exact_target_spec.rb
20
+ spec/spec.opts
21
+ spec/subscriber_list_spec.rb
22
+ Manifest
@@ -0,0 +1,170 @@
1
+ = ExactTarget - A Ruby interface to the ExactTarget API.
2
+
3
+ == Introduction
4
+
5
+ ExactTarget is an email marketing solution provider with an
6
+ http-based api for performing various tasks such as managing
7
+ mailing lists, managing subscribers, and queueing up email
8
+ jobs. This gem is a pure ruby library for accessing that api.
9
+
10
+ == Resources
11
+
12
+ === Installation
13
+
14
+ gem install exact-target
15
+
16
+ === Git Repository
17
+
18
+ http://github.com/ePublishing/exact_target
19
+
20
+ == Prerequisites
21
+
22
+ The ExactTarget gem depends on both Nokogiri and Builder. Both
23
+ should be installed automatically when them gem is installed
24
+ (if not already installed).
25
+
26
+ == Notes
27
+
28
+ Currently this is a partial implementation. None of the
29
+ tracking functionality is yet implemented.
30
+
31
+ == Usage
32
+
33
+ === Setup/Configuration
34
+
35
+ require 'exact_target'
36
+
37
+ ExactTarget.configure do |config|
38
+ config.username = 'my_username'
39
+ config.password = 'my_password'
40
+ end
41
+
42
+ === Account Information
43
+
44
+ # Retrieve subscriber attributes
45
+ ExactTarget.accountinfo_retrieve_attrbs
46
+
47
+ === List Management
48
+
49
+ # Retrieve all list ids
50
+ ExactTarget.list_retrieve
51
+
52
+ # Retrieve list id for given name
53
+ ExactTarget.list_retrieve('Some List')
54
+
55
+ # Retrieve list information by list id
56
+ ExactTarget.list_retrieve(15123512)
57
+
58
+ # Create new list
59
+ ExactTarget.list_add("My Test List", :private)
60
+
61
+ # Rename a list
62
+ ExactTarget.list_edit(15123512, "My RENAMED Test List")
63
+
64
+ # Import new or updated subscribers en mass from a comma-delimited
65
+ # or tab-delimited file into an existing subscriber list.
66
+ ExactTarget.list_import(15123512, 'sometestfile.txt', ['Email Address', 'Field 2', ...])
67
+ ExactTarget.list_import([id_1, id2, ...], 'sometestfile.txt', ['Email Address', 'Field 2', ...])
68
+
69
+ # Request an update on the status of an import.
70
+ ExactTarget.list_importstatus(some_import_id)
71
+
72
+ # Retrieve the profile and preference attributes for all subscribers
73
+ # (or all subscribers with a certain status) on a specified list.
74
+ ExactTarget.list_retrieve_sub(42, 'Active')
75
+
76
+ # Delete a list and all subscribers who belong to the list.
77
+ ExactTarget.list_delete(15123512)
78
+
79
+ # Retrieve all groups in your account.
80
+ ExactTarget.list_retrievegroups
81
+
82
+ # Refresh the membership of an attribute-based (rule-based) group
83
+ # to reflect any changes to your subscribers' attribute values.
84
+ ExactTarget.list_refresh_group(3514)
85
+
86
+ # Request an update on the status of a group refresh.
87
+ ExactTarget.batch_inquire(8912)
88
+
89
+ === Subscriber Management
90
+
91
+ # Add a subscriber to a list.
92
+ subscriber = ExactTarget::Subscriber.new.tap do |s|
93
+ s.email_address = 'test.person@company.com'
94
+ s.full_name = 'George Wills'
95
+ end
96
+ ExactTarget.subscriber_add(1234, subscriber,
97
+ :status => :active,
98
+ :update => true,
99
+ :ChannelMemberID => 5678)
100
+
101
+ # Update the attributes (including email address) and/or status of
102
+ # an existing subscriber. Can be used to reactivate a subscriber
103
+ # who was placed on the master unsubscribe list.
104
+ subscriber = ExactTarget::Subscriber.new.tap do |s|
105
+ s.email_address = 'new.email@company.com'
106
+ s.full_name = 'Frank Jones'
107
+ end
108
+ ExactTarget.subscriber_edit(63718, 'previous@email.com', subscriber,
109
+ :status => :unsub,
110
+ :reason => 'Some reason ...',
111
+ :ChannelMemberID => 5678)
112
+
113
+ # Retrieve all profile and preference attribute data entered for a
114
+ # subscriber on a specific list, or retrieve all attribute data for
115
+ # a subscriber and all lists to which the subscriber belongs.
116
+ ExactTarget.subscriber_retrieve(123456, 'someone@example.com')
117
+ ExactTarget.subscriber_retrieve(123456789)
118
+
119
+ # Delete a subscriber from your database, or remove a subscriber
120
+ # from a specified list.
121
+ ExactTarget.subscriber_delete(112233445566, 'bob@hotmail.com')
122
+ ExactTarget.subscriber_delete(112233445566)
123
+
124
+ # Place a subscriber's (or multiple subscribers') email address on
125
+ # your Master Unsubscribe list so that the email address is never
126
+ # added to any of your subscriber lists.
127
+ ExactTarget.subscriber_masterunsub 'someone@email.com', 'someone.else@email.com', ...
128
+
129
+ === Mailing Management
130
+
131
+ # Retrieve all email IDs or filter by email name and/or date range.
132
+ ExactTarget.email_retrieve
133
+ ExactTarget.email_retrieve('Welcome to Fortune One!')
134
+ ExactTarget.email_retrieve(:start_date => Date.parse('2008-09-15'),
135
+ :end_date => Date.parse('2008-10-15'))
136
+ ExactTarget.email_retrieve('Welcome to Fortune One!',
137
+ :start_date => Date.parse('2008-09-15'),
138
+ :end_date => Date.parse('2008-10-15'))
139
+
140
+ # Create an email from HTML that you send to the ExactTarget application via an API call.
141
+ ExactTarget.email_add('Your email name', 'Your subject line', :body => 'Your HTML email body')
142
+ ExactTarget.email_add('Your email name', 'Your subject line', :file => 'Filename')
143
+
144
+ # Create the text version of an email, which will be displayed
145
+ # to any subscriber whose email client does not support HTML email.
146
+ ExactTarget.email_add_text(email_id, :body => 'Your text email body')
147
+ ExactTarget.email_add_text(email_id, :file => 'Filename')
148
+
149
+ # Retrieve the body of the HTML version of any email in your account.
150
+ ExactTarget.email_retrieve_body(email_id)
151
+
152
+ === Job Initiation
153
+
154
+ # Kick off a mailing (test or live)
155
+ ExactTarget.job_send(email_id,
156
+ [list_id_1, list_id_2, ...],
157
+ :suppress_ids => [list_id_3, ...],
158
+ :from_name => 'John Doe',
159
+ :from_email => 'jd@nowhere.com',
160
+ :additional => 'additional information for job',
161
+ :multipart_mime => true,
162
+ :track_links => false,
163
+ :send_date => '5/3/2011',
164
+ :send_time => '17:35',
165
+ :test_send => true)
166
+
167
+ ---
168
+ Author:: David McCullars <mailto:dmccullars@ePublishing.com>
169
+ Copyright:: (C) 2011 ePublishing
170
+ Licence:: GPL[http://www.gnu.org/copyleft/gpl.html]
@@ -0,0 +1,40 @@
1
+ require 'rake'
2
+ require 'echoe'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ task :default => :gem
7
+
8
+ Echoe.new("exact-target") do |s|
9
+ s.author = "David McCullars"
10
+ s.project = "exact-target"
11
+ s.email = "dmccullars@ePublishing.com"
12
+ s.url = "http://github.com/ePublishing/exact_target"
13
+ s.docs_host = "http://rdoc.info/github/ePublishing/exact_target/master/frames"
14
+ s.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|exceptions|behaviors|exact-target.rb/
15
+ s.clean_pattern += ["ext/lib", "ext/include", "ext/share", "ext/libexact-target-?.??", "ext/bin", "ext/conftest.dSYM"]
16
+ s.summary = <<DONE
17
+ This is a pure-ruby implementation of the ExactTarget api.
18
+ For more information consule http://www.exacttarget.com/.
19
+ DONE
20
+ end
21
+
22
+ desc "Run all specs"
23
+ Spec::Rake::SpecTask.new('spec') do |t|
24
+ t.spec_opts = ['--options', %q("spec/spec.opts")]
25
+ t.spec_files = FileList['spec/**/*_spec.rb']
26
+ t.rcov = true
27
+ t.rcov_opts = ['--exclude', 'spec']
28
+ end
29
+
30
+ desc 'generate API documentation to doc/rdocs/index.html'
31
+ Rake::RDocTask.new do |rd|
32
+ rd.rdoc_dir = 'doc/rdocs'
33
+ rd.main = 'README.rdoc'
34
+ rd.rdoc_files.include 'README.rdoc', 'CHANGELOG', 'lib/**/*.rb'
35
+ rd.rdoc_files.exclude '**/string_ext.rb', '**/net_https_hack.rb'
36
+ rd.options << '--inline-source'
37
+ rd.options << '--line-numbers'
38
+ rd.options << '--all'
39
+ rd.options << '--fileboxes'
40
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{exact-target}
5
+ s.version = "0.0.4"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["David McCullars"]
9
+ s.date = %q{2011-04-11}
10
+ s.description = %q{This is a pure-ruby implementation of the ExactTarget api.
11
+ For more information consule http://www.exacttarget.com/.
12
+ }
13
+ s.email = %q{dmccullars@ePublishing.com}
14
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc"]
15
+ s.files = ["CHANGELOG", "LICENSE", "README.rdoc", "Rakefile", "lib/exact_target.rb", "lib/exact_target/builder_ext.rb", "lib/exact_target/configuration.rb", "lib/exact_target/error.rb", "lib/exact_target/net_https_hack.rb", "lib/exact_target/request_builder.rb", "lib/exact_target/response_class.erb", "lib/exact_target/response_classes.rb", "lib/exact_target/response_handler.rb", "lib/exact_target/string_ext.rb", "spec/exact_target/net_https_hack_spec.rb", "spec/exact_target/response_handler_spec.rb", "spec/exact_target/string_ext_spec.rb", "spec/exact_target_data.yml", "spec/exact_target_spec.rb", "spec/spec.opts", "spec/subscriber_list_spec.rb", "Manifest", "exact-target.gemspec"]
16
+ s.homepage = %q{http://github.com/ePublishing/exact_target}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Exact-target", "--main", "README.rdoc"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{exact-target}
20
+ s.rubygems_version = %q{1.3.6}
21
+ s.summary = %q{This is a pure-ruby implementation of the ExactTarget api. For more information consule http://www.exacttarget.com/.}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -0,0 +1,109 @@
1
+ require 'date'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'nokogiri'
5
+ require 'uri'
6
+
7
+ require 'exact_target/net_https_hack'
8
+ require 'exact_target/builder_ext'
9
+ require 'exact_target/string_ext'
10
+
11
+ require 'exact_target/configuration'
12
+ require 'exact_target/error'
13
+ require 'exact_target/request_builder'
14
+ require 'exact_target/response_classes'
15
+ require 'exact_target/response_handler'
16
+
17
+ # The ExactTarget library is a ruby implementation of the ExactTarget
18
+ # email marketing api. It allows for list/subscriber management,
19
+ # email creation, and job initiation.
20
+ module ExactTarget
21
+
22
+ VERSION = File.read(File.expand_path '../../CHANGELOG', __FILE__)[/v([\d\.]+)\./, 1]
23
+ LOG_PREFIX = "** [ExactTarget] "
24
+
25
+ extend ExactTarget::ResponseClasses
26
+
27
+ class << self
28
+ # The builder object is responsible for building the xml for any given request
29
+ attr_accessor :builder
30
+
31
+ # The handler object is responsible for handling the xml response and returning
32
+ # response data
33
+ attr_accessor :handler
34
+
35
+ # A ExactTarget configuration object. Must act like a hash and return sensible
36
+ # values for all ExactTarget configuration options. See ExactTarget::Configuration.
37
+ attr_accessor :configuration
38
+
39
+ def configure(username=nil, password=nil)
40
+ self.configuration ||= Configuration.new
41
+ configuration.username = username if username
42
+ configuration.password = password if password
43
+ yield(configuration) if block_given?
44
+ self.builder = RequestBuilder.new(configuration)
45
+ self.handler = ResponseHandler.new(configuration)
46
+ nil
47
+ end
48
+
49
+ def verify_configure
50
+ raise "ExactTarget must be configured before using" if configuration.nil? or !configuration.valid?
51
+ end
52
+
53
+ def log(level, message)
54
+ verify_configure
55
+ configuration.logger.send(level, message) unless configuration.logger.nil?
56
+ end
57
+
58
+ def call(method, *args, &block)
59
+ verify_configure
60
+
61
+ request = builder.send(method, *args, &block)
62
+ log :debug, "#{LOG_PREFIX}REQUEST: #{request}"
63
+
64
+ response = send_to_exact_target(request)
65
+ log :debug, "#{LOG_PREFIX}RESPONSE: #{response}"
66
+
67
+ response = parse_response_xml(response)
68
+
69
+ handler.send(method, response)
70
+ end
71
+
72
+ def send_to_exact_target(request)
73
+ verify_configure
74
+ uri = URI.parse "#{configuration.base_url}?qf=xml&xml=#{URI.escape request}"
75
+ http = Net::HTTP.new(uri.host, uri.port)
76
+ http.use_ssl = configuration.secure?
77
+ http.open_timeout = configuration.http_open_timeout
78
+ http.read_timeout = configuration.http_read_timeout
79
+ resp = http.get(uri.request_uri)
80
+ if resp.is_a?(Net::HTTPSuccess)
81
+ resp.body
82
+ else
83
+ resp.error!
84
+ end
85
+ end
86
+
87
+ # Define ExactTarget methods
88
+ (RequestBuilder.instance_methods(false) & ResponseHandler.instance_methods(false)).each do |m|
89
+ define_method(m) do |*args, &block|
90
+ call(m, *args, &block)
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def parse_response_xml(xml)
97
+ verify_configure
98
+ resp = Nokogiri.parse(xml)
99
+ error = resp.xpath('//error[1]').first
100
+ error_description = resp.xpath('//error_description[1]').first
101
+ if error and error_description
102
+ raise Error.new(error.text.to_i, error_description.text)
103
+ else
104
+ resp
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,11 @@
1
+ require 'builder'
2
+
3
+ Builder::XmlBase.class_eval do
4
+
5
+ def tags_from_options!(options, *names)
6
+ names.flatten.each do |name|
7
+ tag! name.to_s, options[name.to_sym].to_s
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,42 @@
1
+ module ExactTarget
2
+ # Used to set up and modify settings for ExactTarget
3
+ class Configuration
4
+
5
+ OPTIONS = [:base_url, :username, :password,
6
+ :http_open_timeout, :http_read_timeout].freeze
7
+
8
+ # The (optional) base URL for accessing ExactTarget (can be http or https).
9
+ # Defaults to 'https://api.dc1.exacttarget.com/integrate.aspx'
10
+ attr_accessor :base_url
11
+
12
+ # The (required) ExactTarget username for making requests
13
+ attr_accessor :username
14
+
15
+ # The (required) ExactTarget password for making requests
16
+ attr_accessor :password
17
+
18
+ # The (optional) logger for outputting request/resposne xml
19
+ attr_accessor :logger
20
+
21
+ # The (optional) HTTP open timeout in seconds (defaults to 2).
22
+ attr_accessor :http_open_timeout
23
+
24
+ # The (optional) HTTP read timeout in seconds (defaults to 5).
25
+ attr_accessor :http_read_timeout
26
+
27
+ def initialize
28
+ @base_url = 'https://api.dc1.exacttarget.com/integrate.aspx'
29
+ @http_open_timeout = 2
30
+ @http_read_timeout = 5
31
+ end
32
+
33
+ def valid?
34
+ [:base_url, :username, :password].none? { |f| send(f).nil? }
35
+ end
36
+
37
+ def secure?
38
+ !!(base_url =~ /^https:/i)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ module ExactTarget
2
+ class Error < Exception
3
+
4
+ attr_reader :id, :description
5
+
6
+ def initialize(id, description)
7
+ @id = id
8
+ @description = description
9
+ end
10
+
11
+ def to_s
12
+ "ExactTarget error ##{id}: #{description}"
13
+ end
14
+
15
+ end
16
+ end