babney-hominid 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ pkg/*
3
+ pkg/*.*
4
+ .svn
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Brian Getting
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,161 @@
1
+ h1. Hominid
2
+
3
+ Hominid is a Ruby gem that provides a wrapper for interacting with the "Mailchimp":http://www.mailchimp.com email marketing service API ("version 1.2":http://www.mailchimp.com/api/1.2/).
4
+
5
+ h2. Installation
6
+
7
+ <pre><code>sudo gem install hominid, :version => '>= 2.0.1', :source => "http://gemcutter.org"</code></pre>
8
+
9
+ Hominid is hosted at "Gemcutter":http://gemcutter.org. Be sure that you have the Gemcutter gem installed if you are having trouble installing Hominid:
10
+
11
+ <pre><code>sudo gem install gemcutter
12
+ gem tumble</code></pre>
13
+
14
+ h2. Configuration
15
+
16
+ You will need to create a "Mailchimp":http://www.mailchimp.com/signup account and get your API key (available at http://admin.mailchimp.com/account/api/) in order to get started.
17
+
18
+ If you are using Hominid inside a Rails application, you can create a config file at @/config/hominid.yml@ with your Mailchimp account information and basic configuration options:
19
+
20
+ <pre><code>development:
21
+ username: USERNAME
22
+ password: PASSWORD
23
+ api_key: API KEY
24
+ send_goodbye: false
25
+ send_notify: false
26
+ double_opt: false
27
+
28
+ ...</code></pre>
29
+
30
+ Run @rake hominid:config@ from within a Rails app to create an empty config file.
31
+ Note: You will need to <pre><code>require 'hominid'</code></pre> in your @Rakefile@ to make this rake task available to your application.
32
+
33
+ h2. Usage
34
+
35
+ Not all API methods are supported (yet). Currently there are classes for working with lists (_Hominid::List_), campaigns (_Hominid::Campaign_) and accessing the helper methods (_Hominid::Helper_).
36
+
37
+ h3. Working with Lists
38
+
39
+ The _Hominid::List_ class is available for working finding lists and working with particular lists. See _Hominid::List_ for more information.
40
+
41
+ h4. List Finder Methods
42
+
43
+ There are finder methods for working with lists. Refer to _Hominid::List_ to see the other finders availables.
44
+
45
+ <pre><code>lists = Hominid::List.all</code></pre>
46
+
47
+ <pre><code>list = Hominid::List.find_by_name("List Name")</code></pre>
48
+
49
+ <pre><code>list = Hominid::List.find(id_or_web_id)</code></pre>
50
+
51
+ h4. Subscribing
52
+
53
+ To subscribe a person or persons to a Mailchimp list:
54
+
55
+ <pre><code>list.subscribe("sample@emailaddress.com")</code></pre>
56
+
57
+ <pre><code>list.subscribe_many([{:EMAIL => 'sample@emailaddress.com', :EMAIL_TYPE => 'html'}, {:EMAIL => 'another@emailaddress.com', :EMAIL_TYPE => 'html'}])</code></pre>
58
+
59
+ h4. Unsubscribing
60
+
61
+ To unsubscribe a person or persons from a Mailchimp list:
62
+
63
+ <pre><code>list.unsubscribe("sample@emailaddress.com")</code></pre>
64
+
65
+ <pre><code>list.unsubscribe_many(['sample@emailaddress.com', 'another@emailaddress.com'])</code></pre>
66
+
67
+ h4. Updating
68
+
69
+ In the following example, we will be changing a person's email address on the Mailchimp list from @sample@ to @another@:
70
+
71
+ <pre><code>list.update_member('sample@emailaddress.com', {:EMAIL => 'another@emailaddress.com'}, 'html')</code></pre>
72
+
73
+ You can also updated other attributes by including the MERGE_VARS that you want to change, such as @EMAIL@, @FNAME@, @LNAME@ and @INTERESTS@. Get a list of merge tags for a particular list by running @list.merge_tags@.
74
+
75
+ h3. Working with Campaigns
76
+
77
+ The _Hominid::Campaign_ class provides methods for working with a campaigns.
78
+
79
+ h4. Campaign Finder Methods
80
+
81
+ There are finder methods for campaigns as well. Refer to _Hominid::Campaign_ to see the other finders available.
82
+
83
+ <pre><code>campaigns = Hominid::Campaign.all</code></pre>
84
+
85
+ <pre><code>campaigns = Hominid::Campaign.find_by_list_name("List Name")</code></pre>
86
+
87
+ h4. Creating a Campaign
88
+
89
+ You can create new campaigns using Hominid as well. Please refer to the documentation in _Hominid::Base_ for more information about the options available when creating a new campaign.
90
+
91
+ <pre><code>new_campaign = Hominid::Campaign.create('regular', options, content, segment_opts, type_opts)</code></pre>
92
+
93
+ h4. Schedule a Campaign
94
+
95
+ As an example of how to work with a particular campaign, use the _Hominid::Campaign_ class. Extending from the previous example, since the _#create_campaign_ method returns the ID of the created campaign, we can use it to instantiate the _Hominid::Campaign_ class and schedule our new campaign to go be delivered 2 days from now:
96
+
97
+ <pre><code>campaign = Hominid::Campaign.new(:id => new_campaign)</code></pre>
98
+
99
+ <pre><code>campaign.schedule_campaign(2.days.from_now)</code></pre>
100
+
101
+ h3. Helper Methods
102
+
103
+ The _Hominid::Helper_ class provides a way to access the helper methods for the Mailchimp API. For example, to create a new folder for filing campaigns:
104
+
105
+ <pre><code>folder = Hominid::Helper.create_folder("Folder Name")</code></pre>
106
+
107
+ h2. Syncing Your Application
108
+
109
+ If you are integrating an application with Mailchimp, Hominid will provide a way for your app to connect with your Mailchimp account. However, it does not provide a way for Mailchimp to connect to your application, which is why Mailchimp has implemented "web hooks":http://www.mailchimp.com/api/webhooks/.
110
+
111
+ The _Hominid::Webhook_ class helps with receiving <tt>POST</tt> data from a Mailchimp webhook:
112
+
113
+ <pre><code>hook = Hominid::Webhook.new(params)
114
+ case hook.event
115
+ when "subscribe"
116
+ user = User.find_by_email(hook.email)
117
+ user.opted_in = true
118
+ user.save
119
+ when "unsubscribe"
120
+ user = User.find_by_email(hook.email)
121
+ user.opted_in = false
122
+ user.save
123
+ when "profile"
124
+ user = User.find_by_email(hook.email)
125
+ user.first_name = hook.first_name
126
+ user.last_name = hook.last_name
127
+ user.email_type = hook.email_type
128
+ user.save
129
+ when "upemail"
130
+ user = User.find_by_email(hook.old_email)
131
+ user.email = hook.new_email
132
+ user.save
133
+ end</code></pre>
134
+
135
+ h2. Contributors
136
+
137
+ Hominid is maintained by "Brian Getting":http://terra-firma-design.com. A very special thank-you to "Michael Strüder":http://github.com/mikezter for all of his hard work. Also, Hominid wouldn't be anywhere near as awesome as it is today without fantastic contributions and inspiration from:
138
+
139
+ * "Alan Harper":http://github.com/aussiegeek
140
+ * "Will":http://github.com/willinfront
141
+ * "Ben Woosley":http://github.com/Empact
142
+ * "banker":http://github.com/banker
143
+ * "Kristoffer Renholm":http://github.com/renholm
144
+ * "Wiktor Schmidt":http://github.com/netguru
145
+ * "ron":http://github.com/ron
146
+ * "Matthew Carlson":http://mandarinsoda.com/
147
+ * "Kelly Mahan":http://digimedia.com/
148
+ * "C.G. Brown":http://www.projectlocker.com/
149
+
150
+ h2. Note on Patches/Pull Requests
151
+
152
+ # Fork the project.
153
+ # Make your feature addition or bug fix.
154
+ # Add tests for it. This is important so I don't break it in a future version unintentionally.
155
+ # Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
156
+ # Send me a pull request. Bonus points for topic branches.
157
+
158
+ h2. Copyright
159
+
160
+ Copyright (c) 2009 Brian Getting. See LICENSE for details.
161
+
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "babney-hominid"
8
+ gem.summary = %Q{Hominid is a Ruby gem for interacting with the Mailchimp API.}
9
+ gem.description = %Q{Hominid is a Ruby gem that provides a wrapper for interacting with the Mailchimp email marketing service API.}
10
+ gem.email = "brian@terra-firma-design.com"
11
+ gem.homepage = "http://github.com/bgetting/hominid"
12
+ gem.authors = ["Brian Getting", "Michael Strüder"]
13
+ gem.add_development_dependency "shoulda"
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION')
47
+ version = File.read('VERSION')
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "hominid #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.1
@@ -0,0 +1,60 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{hominid}
8
+ s.version = "2.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Brian Getting", "Michael Str\303\274der"]
12
+ s.date = %q{2009-11-11}
13
+ s.description = %q{Hominid is a Ruby gem that provides a wrapper for interacting with the Mailchimp email marketing service API.}
14
+ s.email = %q{brian@terra-firma-design.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.textile",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "hominid.gemspec",
26
+ "hominid.yml.tpl",
27
+ "lib/hominid.rb",
28
+ "lib/hominid/base.rb",
29
+ "lib/hominid/campaign.rb",
30
+ "lib/hominid/helper.rb",
31
+ "lib/hominid/list.rb",
32
+ "lib/hominid/webhook.rb",
33
+ "tasks/rails/hominid.rake",
34
+ "test/hominid_test.rb",
35
+ "test/test_helper.rb"
36
+ ]
37
+ s.homepage = %q{http://github.com/bgetting/hominid}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = %q{1.3.5}
41
+ s.summary = %q{Hominid is a Ruby gem for interacting with the Mailchimp API.}
42
+ s.test_files = [
43
+ "test/hominid_test.rb",
44
+ "test/test_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<shoulda>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ end
59
+ end
60
+
@@ -0,0 +1,25 @@
1
+ # Get your API key at http://admin.mailchimp.com/account/api/
2
+
3
+ development:
4
+ username:
5
+ password:
6
+ api_key:
7
+ send_goodbye: false
8
+ send_notify: false
9
+ double_opt_in: false
10
+
11
+ test:
12
+ username:
13
+ password:
14
+ api_key:
15
+ send_goodbye: false
16
+ send_notify: false
17
+ double_opt_in: false
18
+
19
+ production:
20
+ username:
21
+ password:
22
+ api_key:
23
+ send_goodbye: false
24
+ send_notify: false
25
+ double_opt_in: false
@@ -0,0 +1,54 @@
1
+ require 'xmlrpc/client'
2
+ require 'ostruct'
3
+
4
+ module Hominid
5
+
6
+ class StandardError < ::StandardError
7
+ end
8
+
9
+ class APIError < StandardError
10
+ def initialize(error)
11
+ super("<#{error.faultCode}> #{error.message}")
12
+ end
13
+ end
14
+
15
+ class ListError < APIError
16
+ end
17
+
18
+ class ListEmailError < ListError
19
+ end
20
+
21
+ class ListMergeError < ListError
22
+ end
23
+
24
+ class AlreadySubscribed < ListEmailError
25
+ end
26
+
27
+ class AlreadyUnsubscribed < ListEmailError
28
+ end
29
+
30
+ class NotExists < ListEmailError
31
+ end
32
+
33
+ class NotSubscribed < ListEmailError
34
+ end
35
+
36
+ class CommunicationError < StandardError
37
+ def initialize(message)
38
+ super(message)
39
+ end
40
+ end
41
+ end
42
+
43
+ begin
44
+ # include the provided rake task
45
+ require 'rake'
46
+ unless Rake::Task.task_defined? "hominid:config"
47
+ load File.join(File.dirname(__FILE__), '..', 'tasks', 'rails', 'hominid.rake')
48
+ end
49
+ rescue LoadError
50
+ # silently skip rake task inclusion unless the rake gem is installed
51
+ end
52
+
53
+ require 'hominid/base'
54
+
@@ -0,0 +1,90 @@
1
+ module Hominid
2
+ class Base
3
+
4
+ # MailChimp API Documentation: http://www.mailchimp.com/api/1.2/
5
+ MAILCHIMP_API_VERSION = "1.2"
6
+
7
+ def initialize(config = {})
8
+ if defined?(Rails.root) && (!config || config.empty?)
9
+ config = YAML.load(File.open("#{Rails.root}/config/hominid.yml"))[Rails.env].symbolize_keys
10
+ end
11
+ api_endpoint = config[:api_key].split('-').last
12
+ config.merge(:username => config[:username].to_s, :password => config[:password].to_s)
13
+ defaults = {:send_welcome => false,
14
+ :double_opt_in => false,
15
+ :update_existing => true,
16
+ :replace_interests => true,
17
+ :merge_tags => {},
18
+ :secure => false}
19
+ @config = defaults.merge(config).freeze
20
+ if config[:secure]
21
+ @chimpApi = XMLRPC::Client.new2("https://#{api_endpoint}.api.mailchimp.com/#{MAILCHIMP_API_VERSION}/")
22
+ else
23
+ @chimpApi = XMLRPC::Client.new2("http://#{api_endpoint}.api.mailchimp.com/#{MAILCHIMP_API_VERSION}/")
24
+ end
25
+ end
26
+
27
+ # Security related methods
28
+ # --------------------------------
29
+
30
+ def add_api_key
31
+ @chimpApi.call("apikeyAdd", *@config.values_at(:username, :password, :api_key))
32
+ end
33
+
34
+ def expire_api_key
35
+ @chimpApi.call("apikeyExpire", *@config.values_at(:username, :password, :api_key))
36
+ end
37
+
38
+ def api_keys(include_expired = false)
39
+ username, password = *@config.values_at(:username, :password)
40
+ @chimpApi.call("apikeys", username, password, include_expired)
41
+ end
42
+
43
+ # Used internally by Hominid
44
+ # --------------------------------
45
+
46
+ # handle common cases for which the Mailchimp API would raise Exceptions
47
+ def clean_merge_tags(merge_tags)
48
+ return {} unless merge_tags.is_a? Hash
49
+ merge_tags.each do |key, value|
50
+ if merge_tags[key].is_a? String
51
+ merge_tags[key] = value.gsub("\v", '')
52
+ elsif merge_tags[key].nil?
53
+ merge_tags[key] = ''
54
+ end
55
+ end
56
+ end
57
+
58
+ def apply_defaults_to(options)
59
+ @config.merge(options)
60
+ end
61
+
62
+ def call(method, *args)
63
+ @chimpApi.call(method, @config[:api_key], *args)
64
+ rescue XMLRPC::FaultException => error
65
+ case error.faultCode
66
+ when 230
67
+ raise AlreadySubscribed.new(error)
68
+ when 231
69
+ raise AlreadyUnsubscribed.new(error)
70
+ when 232
71
+ raise NotExists.new(error)
72
+ when 233, 215
73
+ raise NotSubscribed.new(error)
74
+ else
75
+ raise APIError.new(error)
76
+ end
77
+ rescue RuntimeError => error
78
+ if error.message =~ /Wrong type NilClass\. Not allowed!/
79
+ hashes = args.select{|a| a.is_a? Hash}
80
+ errors = hashes.select{|k, v| v.nil? }.collect{ |k, v| "#{k} is Nil." }.join(' ')
81
+ raise CommunicationError.new(errors)
82
+ else
83
+ raise error
84
+ end
85
+ rescue Exception => error
86
+ raise CommunicationError.new(error.message)
87
+ end
88
+ end
89
+ end
90
+
@@ -0,0 +1,172 @@
1
+ module Hominid
2
+
3
+ class Campaign < Base
4
+
5
+ # Campaign related methods
6
+ # --------------------------------
7
+
8
+ attr_reader :campaign_id
9
+ attr_reader :attributes
10
+
11
+ def initialize(*args)
12
+ options = args.last.is_a?(Hash) ? args.last : {}
13
+ raise StandardError.new('Please provide a Campaign ID.') unless options[:id]
14
+ @campaign_id = options.delete(:id)
15
+ @attributes = options.delete(:attributes)
16
+ super(options)
17
+ end
18
+
19
+ def self.all
20
+ # Get all campaigns for this mailchimp account
21
+ new(:id => 0).call("campaigns").to_a.collect { |c| Campaign.new(:id => c.delete('id'), :attributes => c) }
22
+ end
23
+
24
+ def self.find_by_list_name(list_name)
25
+ new(:id => 0).call("campaigns", {:list_id => List.find_by_name(list_name).list_id}).to_a.collect { |c| Campaign.new(:id=> c.delete('id'), :attributes => c) }
26
+ end
27
+
28
+ def self.find_by_list_id(list_id)
29
+ # Find all campaigns for the given list
30
+ new(:id => 0).call("campaigns", {:list_id => list_id}).to_a.collect { |c| Campaign.new(:id=> c.delete('id'), :attributes => c) }
31
+ end
32
+
33
+ def self.find_by_title(title)
34
+ # Find campaign by title
35
+ all.find { |c| c.attributes['title'] =~ /#{title}/ }
36
+ end
37
+
38
+ def self.find_by_type(type)
39
+ # Find campaign by type. Possible choices are:
40
+ # 'regular'
41
+ # 'plaintext'
42
+ # 'absplit'
43
+ # 'rss'
44
+ # 'inspection'
45
+ # 'trans'
46
+ # 'auto'
47
+ all.find { |campaign| campaign.attributes['type'] =~ /#{type}/ }
48
+ end
49
+
50
+ def self.find_by_web_id(web_id)
51
+ # Find campaigns by web_id
52
+ all.find { |campaign| campaign.attributes['web_id'] == web_id.to_i }
53
+ end
54
+
55
+ def self.find_by_id(id)
56
+ # Find campaign by id
57
+ all.find { |campaign| (campaign.campaign_id == id.to_s) }
58
+ end
59
+
60
+ def self.find(id_or_web_id)
61
+ # Campaign finder method
62
+ all = self.all
63
+ campaign = self.find_by_id(id_or_web_id.to_s).to_a + self.find_by_web_id(id_or_web_id.to_i).to_a
64
+ return campaign.blank? ? nil : campaign.first
65
+ end
66
+
67
+ def self.create(type = 'regular', options = {}, content = {}, segment_options = {}, type_opts = {})
68
+ # Create a new campaign
69
+ # The options hash should be structured as follows:
70
+ #
71
+ # :list_id = (string) The ID of the list to send this campaign to.
72
+ # :subject = (string) The subject of the campaign.
73
+ # :from_email = (string) The email address this campaign will come from.
74
+ # :from_name = (string) The name that this campaign will come from.
75
+ # :to_email = (string) The To: name recipients will see.
76
+ # :template_id = (integer) The ID of the template to use for this campaign (optional).
77
+ # :folder_id = (integer) The ID of the folder to file this campaign in (optional).
78
+ # :tracking = (array) What to track for this campaign (optional).
79
+ # :title = (string) Internal title for this campaign (optional).
80
+ # :authenticate = (boolean) Set to true to authenticate campaign (optional).
81
+ # :analytics = (array) Google analytics tags (optional).
82
+ # :auto_footer = (boolean) Auto-generate the footer (optional)?
83
+ # :inline_css = (boolean) Inline the CSS styles (optional)?
84
+ # :generate_text = (boolean) Auto-generate text from HTML email (optional)?
85
+ #
86
+ # Visit http://www.mailchimp.com/api/1.2/campaigncreate.func.php for more information about creating
87
+ # campaigns via the API.
88
+ #
89
+ new(:id => 0).call("campaignCreate", type, options, content, segment_options, type_opts)
90
+ ## TODO: Return the new campaign with the ID returned from the API
91
+ end
92
+
93
+ def self.templates
94
+ # Get the templates for this account
95
+ new(:id => 0).call("campaignTemplates")
96
+ end
97
+
98
+ def add_order(order)
99
+ # Attach Ecommerce Order Information to a campaign.
100
+ # The order hash should be structured as follows:
101
+ #
102
+ # :id = (string) the order id
103
+ # :email_id = (string) email id of the subscriber (mc_eid query string)
104
+ # :total = (double) Show only campaigns with this from_name.
105
+ # :shipping = (string) *optional - the total paid for shipping fees.
106
+ # :tax = (string) *optional - the total tax paid.
107
+ # :store_id = (string) a unique id for the store sending the order in
108
+ # :store_name = (string) *optional - A readable name for the store, typicaly the hostname.
109
+ # :plugin_id = (string) the MailChimp-assigned Plugin Id. Using 1214 for the moment.
110
+ # :items = (array) the individual line items for an order, using the following keys:
111
+ #
112
+ # :line_num = (integer) *optional - line number of the item on the order
113
+ # :product_id = (integer) internal product id
114
+ # :product_name = (string) the name for the product_id associated with the item
115
+ # :category_id = (integer) internal id for the (main) category associated with product
116
+ # :category_name = (string) the category name for the category id
117
+ # :qty = (double) the quantity of items ordered
118
+ # :cost = (double) the cost of a single item (i.e., not the extended cost of the line)
119
+ order = order.merge(:campaign_id => @campaign_id)
120
+ call("campaignEcommAddOrder", order)
121
+ end
122
+
123
+ def campaign_stats()
124
+ # Get the stats of a campaign
125
+ call("campaignStats", @campaign_id)
126
+ end
127
+
128
+ # Get the HTML & text content for a campaign
129
+ # :for_archive = (boolean) default true, true returns the content as it would appear in the archive, false returns the raw HTML/text
130
+ def campaign_content(for_archive = true)
131
+ # Get the content of a campaign
132
+ call("campaignContent", @campaign_id, for_archive)
133
+ end
134
+
135
+ def delete_campaign()
136
+ # Delete a campaign
137
+ call("campaignDelete", @campaign_id)
138
+ end
139
+
140
+ def replicate_campaign()
141
+ # Replicate a campaign (returns ID of new campaign)
142
+ call("campaignReplicate", @campaign_id)
143
+ end
144
+
145
+ def schedule_campaign(time = "#{1.day.from_now}")
146
+ # Schedule a campaign
147
+ ## TODO: Add support for A/B Split scheduling
148
+ call("campaignSchedule", @campaign_id, time)
149
+ end
150
+
151
+ def send_now()
152
+ # Send a campaign
153
+ call("campaignSendNow", @campaign_id)
154
+ end
155
+
156
+ # Send a test of a campaign
157
+ def send_test(emails = {})
158
+ call("campaignSendTest", @campaign_id, emails)
159
+ end
160
+
161
+ def update(name, value)
162
+ # Update a campaign
163
+ call("campaignUpdate", @campaign_id, name, value)
164
+ end
165
+
166
+ def unschedule()
167
+ # Unschedule a campaign
168
+ call("campaignUnschedule", @campaign_id)
169
+ end
170
+ end
171
+ end
172
+
@@ -0,0 +1,45 @@
1
+ module Hominid
2
+
3
+ class Helper < Base
4
+
5
+ # Helper methods
6
+ # --------------------------------
7
+
8
+ def self.account_details(options = {})
9
+ # Get details for this account.
10
+ new(options).call("getAccountDetails")
11
+ end
12
+
13
+ def self.convert_css_to_inline(html, strip_css = false, options = {})
14
+ # Convert CSS styles to inline styles and (optionally) remove original styles
15
+ new.call("inlineCss", html, strip_css)
16
+ end
17
+
18
+ def self.create_folder(name, options = {})
19
+ # Create a new folder to file campaigns in
20
+ new(options).call("createFolder", name)
21
+ end
22
+
23
+ def self.generate_text(type, content, options = {})
24
+ # Have HTML content auto-converted to a text-only format.
25
+ # The options for text type are:
26
+ # 'html' => Expects a string of HTML(default).
27
+ # 'template' => Expects an array.
28
+ # 'url' => Expects a valid and public URL.
29
+ # 'cid' => Expects a campaign ID.
30
+ # 'tid' => Expects a template ID.
31
+ new(options).call("generateText", type, content)
32
+ end
33
+
34
+ def self.html_to_text(content, options = {})
35
+ # Convert HTML content to text
36
+ new(options).call("generateText", 'html', content)
37
+ end
38
+
39
+ def self.ping(options = {})
40
+ # Ping the Mailchimp API
41
+ new(options).call("ping")
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,150 @@
1
+ module Hominid
2
+
3
+ class List < Base
4
+
5
+ # List related methods
6
+ # --------------------------------
7
+
8
+ attr_reader :list_id
9
+ attr_reader :attributes
10
+
11
+ def initialize(*args)
12
+ options = args.last.is_a?(Hash) ? args.last : {}
13
+ raise StandardError.new('Please provide a List ID.') unless options[:id]
14
+ @list_id = options.delete(:id)
15
+ @attributes = options.delete(:attributes)
16
+ super(options)
17
+ end
18
+
19
+ def self.all
20
+ # Get all lists for this mailchimp account
21
+ new(:id => 0).call("lists").to_a.collect { |list| List.new(:id => list.delete('id'), :attributes => list) }
22
+ end
23
+
24
+ def self.find_by_name(name)
25
+ # Find list by name
26
+ all.find { |list| list.attributes['name'] =~ /#{name}/ }
27
+ end
28
+
29
+ def self.find_by_web_id(web_id)
30
+ # Find list by name
31
+ all.find { |list| (list.attributes['web_id'] == web_id.to_i) }
32
+ end
33
+
34
+ def self.find_by_id(id)
35
+ # Find list by id
36
+ all.find { |list| (list.list_id == id.to_s) }
37
+ end
38
+
39
+ def self.find(id_or_web_id)
40
+ # List finder method
41
+ all = self.all
42
+ list = self.find_by_id(id_or_web_id.to_s).to_a + self.find_by_web_id(id_or_web_id.to_i).to_a
43
+ return list.blank? ? nil : list.first
44
+ end
45
+
46
+ def create_group(group)
47
+ # Add an interest group to a list
48
+ call("listInterestGroupAdd", @list_id, group)
49
+ end
50
+ alias :interest_group_add :create_group
51
+
52
+ def create_tag(tag, name, required = false)
53
+ # Add a merge tag to a list
54
+ call("listMergeVarAdd", @list_id, tag, name, required)
55
+ end
56
+ alias :merge_var_add :create_tag
57
+
58
+ def delete_group(group)
59
+ # Delete an interest group for a list
60
+ call("listInterestGroupDel", @list_id, group)
61
+ end
62
+ alias :interest_group_del :delete_group
63
+
64
+ def delete_tag(tag)
65
+ # Delete a merge tag and all its members
66
+ call("listMergeVarDel", @list_id, tag)
67
+ end
68
+ alias :merge_var_del :delete_tag
69
+
70
+ def groups()
71
+ # Get the interest groups for a list
72
+ call("listInterestGroups", @list_id)
73
+ end
74
+ alias :interest_groups :groups
75
+
76
+
77
+ def member_info(email)
78
+ # Get a member of a list
79
+ call("listMemberInfo", @list_id, email)
80
+ end
81
+
82
+ def members(status = "subscribed", since = "2000-01-01 00:00:00", start = 0, limit = 100)
83
+ # Get members of a list based on status
84
+ # Select members based on one of the following statuses:
85
+ # 'subscribed'
86
+ # 'unsubscribed'
87
+ # 'cleaned'
88
+ # 'updated'
89
+ #
90
+ # Select members that have updated their status or profile by providing
91
+ # a "since" date in the format of YYYY-MM-DD HH:MM:SS
92
+ call("listMembers", @list_id, status, since, start, limit)
93
+ end
94
+
95
+ def merge_tags()
96
+ # Get the merge tags for a list
97
+ call("listMergeVars", @list_id)
98
+ end
99
+ alias :merge_vars :merge_tags
100
+
101
+ def subscribe(email, options = {})
102
+ # Subscribe a member to this list
103
+ merge_tags = clean_merge_tags options[:merge_tags]
104
+ options = apply_defaults_to({:email_type => "html"}.merge(options))
105
+ call(
106
+ "listSubscribe",
107
+ @list_id,
108
+ email,
109
+ merge_tags,
110
+ *options.values_at(
111
+ :email_type,
112
+ :double_opt_in,
113
+ :update_existing,
114
+ :replace_interests,
115
+ :send_welcome
116
+ )
117
+ )
118
+ end
119
+
120
+ def subscribe_many(subscribers, options = {})
121
+ # Subscribe an array of email addresses
122
+ # subscribers(array) = [{:EMAIL => 'example@email.com', :EMAIL_TYPE => 'html'}]
123
+ subscribers = subscribers.collect { |subscriber| clean_merge_tags(subscriber) }
124
+ options = apply_defaults_to({:update_existing => true}.merge(options))
125
+ call("listBatchSubscribe", @list_id, subscribers, *options.values_at(:double_opt_in, :update_existing, :replace_interests))
126
+ end
127
+ alias :batch_subscribe :subscribe_many
128
+
129
+ def unsubscribe(current_email, options = {})
130
+ # Unsubscribe a list member
131
+ options = apply_defaults_to({:delete_member => true}.merge(options))
132
+ call("listUnsubscribe", @list_id, current_email, *options.values_at(:delete_member, :send_goodbye, :send_notify))
133
+ end
134
+
135
+ def unsubscribe_many(emails, options = {})
136
+ # Unsubscribe an array of email addresses
137
+ # emails(array) = ['first@email.com', 'second@email.com']
138
+ options = apply_defaults_to({:delete_member => true}.merge(options))
139
+ call("listBatchUnsubscribe", @list_id, emails, *options.values_at(:delete_member, :send_goodbye, :send_notify))
140
+ end
141
+ alias :batch_unsubscribe :unsubscribe_many
142
+
143
+ def update_member(current_email, merge_tags = {}, email_type = "html", replace_interests = true)
144
+ # Update a member of this list
145
+ call("listUpdateMember", @list_id, current_email, merge_tags, email_type, replace_interests)
146
+ end
147
+
148
+ end
149
+ end
150
+
@@ -0,0 +1,131 @@
1
+ module Hominid
2
+
3
+ class Webhook < Base
4
+ # Expects a hash of POST data generated from Mailchimp:
5
+ #
6
+ # "type": "unsubscribe",
7
+ # "fired_at": "2009-03-26 21:54:00",
8
+ # "data[email]": "sample@emailaddress.com"
9
+ #
10
+ # Simple Usage:
11
+ #
12
+ # h = Hominid::Webhook.new(params)
13
+ #
14
+ # Sample params from Mailchimp webhook:
15
+ # params => { "type" => "subscribe",
16
+ # "fired_at" => "2009-03-26 21:35:57",
17
+ # "data" => { "id" => "8a25ff1d98",
18
+ # "list_id" => "8a25ff1d98",
19
+ # "email" => "api@mailchimp.com",
20
+ # "email_type" => "html",
21
+ # "merges" => {"EMAIL" => "api@mailchimp.com",
22
+ # "FNAME" => "Brian",
23
+ # "LNAME" => "Getting",
24
+ # "INTERESTS" => "Group1,Group2"},
25
+ # "ip_opt" => "10.20.10.30",
26
+ # "ip_signup" => "10.20.10.30" }}
27
+ #
28
+ # Returns an object with the following methods (NOTE: Not all methods are available
29
+ # for all event types. Refer to http://www.mailchimp.com/api/webhooks/ for information
30
+ # on what data will be available for each event):
31
+ #
32
+ # h.event <= (String) The event that fired the request. Possible events are:
33
+ # "subscribe", "unsubscribe", "profile", "upemail", "cleaned"
34
+ # h.fired_at <= (Datetime) When the webhook request was fired.
35
+ # h.id <= (String) The ID of the webhook request.
36
+ # h.list_id <= (String) The ID of the list that generated the request.
37
+ # h.email <= (String) The email address of the subscriber that generated the request.
38
+ # h.email_type <= (String) The email type of the subscriber that generated the request.
39
+ # h.first_name <= (String) The first name of the subscriber (if available).
40
+ # h.last_name <= (String) The first name of the subscriber (if available).
41
+ # h.interests <= (Array) An array of the interest groups.
42
+ # h.ip_opt <= (String) The opt in IP address.
43
+ # h.ip_signup <= (String) The signup IP address.
44
+ #
45
+
46
+ attr_reader :request
47
+
48
+ def initialize(*args)
49
+ post_data = args.last
50
+ raise HominidError.new('Please provide the POST data from a Mailchimp webhook request.') unless post_data.is_a?(Hash)
51
+ post_data.merge!({"event" => "#{post_data.delete('type')}"})
52
+ @request = hash_to_object(post_data)
53
+ end
54
+
55
+
56
+ def email
57
+ self.request.data.email if self.request.data.email
58
+ end
59
+
60
+ def email_type
61
+ self.request.data.email_type if self.request.data.email_type
62
+ end
63
+
64
+ def event
65
+ self.request.event if self.request.event
66
+ end
67
+
68
+ def fired_at
69
+ self.request.fired_at.to_datetime if self.request.fired_at
70
+ end
71
+
72
+ def first_name
73
+ self.request.data.merges.fname if self.request.data.merges.fname
74
+ end
75
+
76
+ def last_name
77
+ self.request.data.merges.lname if self.request.data.merges.lname
78
+ end
79
+
80
+ def id
81
+ self.request.data.id if self.request.data.id
82
+ end
83
+
84
+ def interests
85
+ self.request.data.merges.interests.split(',') if self.request.data.merges.interests
86
+ end
87
+
88
+ def ip_opt
89
+ self.request.data.ip_opt if self.request.data.ip_opt
90
+ end
91
+
92
+ def ip_signup
93
+ self.request.data.ip_signup if self.request.data.ip_signup
94
+ end
95
+
96
+ def list_id
97
+ self.request.data.list_id if self.request.data.list_id
98
+ end
99
+
100
+ def new_email
101
+ self.request.data.new_email if self.request.data.new_email
102
+ end
103
+
104
+ def old_email
105
+ self.request.data.old_email if self.request.data.old_email
106
+ end
107
+
108
+ def reason
109
+ self.request.data.reason if self.request.data.reason
110
+ end
111
+
112
+ private
113
+
114
+ def hash_to_object(object)
115
+ return case object
116
+ when Hash
117
+ object = object.clone
118
+ object.each do |key, value|
119
+ object[key.downcase] = hash_to_object(value)
120
+ end
121
+ OpenStruct.new(object)
122
+ when Array
123
+ object = object.clone
124
+ object.map! { |i| hash_to_object(i) }
125
+ else
126
+ object
127
+ end
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ namespace :hominid do
3
+ # Task to create the config file
4
+ desc "Generate a Hominid config file"
5
+ task :config => :environment do |t|
6
+ require 'fileutils'
7
+ if defined?(Rails.root)
8
+ config_file = File.join(Rails.root, 'config', 'hominid.yml')
9
+ template_file = File.join(File.dirname(__FILE__), '..', '..', 'hominid.yml.tpl')
10
+ unless File.exists? config_file
11
+ FileUtils.cp(
12
+ File.join(File.dirname(__FILE__), '..', '..', 'hominid.yml.tpl'),
13
+ File.join(Rails.root, 'config', 'hominid.yml')
14
+ )
15
+ puts 'Please edit config/hominid.yml to your needs.'
16
+ else
17
+ puts 'We left your existing config/hominid.yml untouched.'
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class HominidTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'hominid'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: babney-hominid
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Getting
8
+ - "Michael Str\xC3\xBCder"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-11-18 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: shoulda
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ description: Hominid is a Ruby gem that provides a wrapper for interacting with the Mailchimp email marketing service API.
27
+ email: brian@terra-firma-design.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - LICENSE
34
+ - README.textile
35
+ files:
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.textile
39
+ - Rakefile
40
+ - VERSION
41
+ - hominid.gemspec
42
+ - hominid.yml.tpl
43
+ - lib/hominid.rb
44
+ - lib/hominid/base.rb
45
+ - lib/hominid/campaign.rb
46
+ - lib/hominid/helper.rb
47
+ - lib/hominid/list.rb
48
+ - lib/hominid/webhook.rb
49
+ - tasks/rails/hominid.rake
50
+ - test/hominid_test.rb
51
+ - test/test_helper.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/bgetting/hominid
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --charset=UTF-8
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.5
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Hominid is a Ruby gem for interacting with the Mailchimp API.
80
+ test_files:
81
+ - test/hominid_test.rb
82
+ - test/test_helper.rb