exact-target 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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