babney-hominid 2.0.1
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/.gitignore +4 -0
- data/LICENSE +20 -0
- data/README.textile +161 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/hominid.gemspec +60 -0
- data/hominid.yml.tpl +25 -0
- data/lib/hominid.rb +54 -0
- data/lib/hominid/base.rb +90 -0
- data/lib/hominid/campaign.rb +172 -0
- data/lib/hominid/helper.rb +45 -0
- data/lib/hominid/list.rb +150 -0
- data/lib/hominid/webhook.rb +131 -0
- data/tasks/rails/hominid.rake +22 -0
- data/test/hominid_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +82 -0
data/.gitignore
ADDED
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.
|
data/README.textile
ADDED
|
@@ -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
|
+
|
data/Rakefile
ADDED
|
@@ -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
|
data/hominid.gemspec
ADDED
|
@@ -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
|
+
|
data/hominid.yml.tpl
ADDED
|
@@ -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
|
data/lib/hominid.rb
ADDED
|
@@ -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
|
+
|
data/lib/hominid/base.rb
ADDED
|
@@ -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
|
data/lib/hominid/list.rb
ADDED
|
@@ -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
|
+
|
data/test/test_helper.rb
ADDED
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
|