monkey_party 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitignore +6 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +26 -0
  4. data/Rakefile +63 -0
  5. data/VERSION.yml +5 -0
  6. data/features/create_and_add_api_key.feature +21 -0
  7. data/features/list_subscribe.feature +13 -0
  8. data/features/list_unsubscribe.feature +14 -0
  9. data/features/step_definitions/create_and_add_api_key_steps.rb +45 -0
  10. data/features/step_definitions/list_steps.rb +17 -0
  11. data/features/step_definitions/list_unsubscribe_steps.rb +17 -0
  12. data/features/support/env.rb +4 -0
  13. data/features/support/mailchimp/account.rb +8 -0
  14. data/features/support/mailchimp/account.yml.example +2 -0
  15. data/features/support/mailchimp/cleaner.rb +3 -0
  16. data/lib/monkey_party.rb +14 -0
  17. data/lib/monkey_party/account.rb +48 -0
  18. data/lib/monkey_party/base.rb +30 -0
  19. data/lib/monkey_party/error.rb +9 -0
  20. data/lib/monkey_party/list.rb +99 -0
  21. data/lib/monkey_party/subscriber.rb +30 -0
  22. data/monkey_party.gemspec +87 -0
  23. data/test/fixtures/batch_subscribe_failed.xml +28 -0
  24. data/test/fixtures/batch_subscribe_successful.xml +12 -0
  25. data/test/fixtures/batch_unsubscribe_failed.xml +19 -0
  26. data/test/fixtures/batch_unsubscribe_successful.xml +12 -0
  27. data/test/fixtures/lists_failed.xml +11 -0
  28. data/test/fixtures/lists_successful.xml +16 -0
  29. data/test/fixtures/login_failed.xml +11 -0
  30. data/test/fixtures/login_successful.xml +8 -0
  31. data/test/monkey_party/account_test.rb +91 -0
  32. data/test/monkey_party/error_test.rb +18 -0
  33. data/test/monkey_party/list_test.rb +173 -0
  34. data/test/monkey_party/subscriber_test.rb +44 -0
  35. data/test/test_helper.rb +31 -0
  36. metadata +153 -0
@@ -0,0 +1,6 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ features/support/mailchimp/account.yml
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Dan Pickett
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,26 @@
1
+ = monkey_party
2
+
3
+ An extremely young API for interacting with the MailChimp API
4
+
5
+ Uses the excellent HTTParty and HappyMapper tools and is well tested
6
+
7
+ Currently only supports
8
+
9
+ * adding api keys
10
+ * finding lists by name
11
+ * batch subscribing
12
+ * unsubscribing
13
+
14
+ == Example Usage
15
+
16
+ account = MonkeyParty::Account.login("monkey_username", "party_password")
17
+ list = MonkeyParty::List.find_by_name("list_name")
18
+ list.create_subscribers([MonkeyParty::Subscriber.new("user@example.com")])
19
+
20
+ == TODO
21
+ * Batch subscribe does not allow you to resubscribe members - implement individual subscribe method
22
+ * Clean up after cucumber features are run
23
+
24
+ == Copyright
25
+
26
+ Copyright (c) 2009 Dan Pickett. See LICENSE for details.
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "monkey_party"
8
+ gem.summary = %Q{mailchimp wrapper}
9
+ gem.email = "dpickett@enlightsolutions.com"
10
+ gem.homepage = "http://github.com/dpickett/monkey_party"
11
+ gem.authors = ["Dan Pickett"]
12
+ gem.add_dependency("httparty", ">= 0.5.2")
13
+ gem.add_dependency("happymapper", ">= 0.3.0")
14
+ gem.add_dependency("configatron", ">= 2.6.3")
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ begin
22
+ require 'cucumber'
23
+ require 'cucumber/rake/task'
24
+
25
+ Cucumber::Rake::Task.new(:cucumber) do |t|
26
+ t.cucumber_opts = "--format pretty" # Any valid command line option can go here.
27
+ end
28
+
29
+ rescue LoadError
30
+ puts "Cucumber not installed. You will not be able to run features"
31
+ end
32
+
33
+ require 'rake/rdoctask'
34
+ Rake::RDocTask.new do |rdoc|
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = 'monkey_party'
37
+ rdoc.options << '--line-numbers' << '--inline-source'
38
+ rdoc.rdoc_files.include('README*')
39
+ rdoc.rdoc_files.include('lib/**/*.rb')
40
+ end
41
+
42
+ require 'rake/testtask'
43
+ Rake::TestTask.new(:test) do |test|
44
+ test.libs << 'lib' << 'test'
45
+ test.pattern = 'test/**/*_test.rb'
46
+ test.verbose = false
47
+ end
48
+
49
+ begin
50
+ require 'rcov/rcovtask'
51
+ Rcov::RcovTask.new do |test|
52
+ test.libs << 'test'
53
+ test.pattern = 'test/**/*_test.rb'
54
+ test.verbose = true
55
+ end
56
+ rescue LoadError
57
+ task :rcov do
58
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
59
+ end
60
+ end
61
+
62
+
63
+ task :default => :test
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :build:
5
+ :minor: 2
@@ -0,0 +1,21 @@
1
+ Feature: Create an api key
2
+ In order to interact with the MailChimp Service
3
+ As a developer
4
+ I want to login and generate an api key
5
+
6
+ Scenario: Successful Login
7
+ Given I have a valid mailchimp account
8
+ When I attempt to login with the proper credentials
9
+ Then I should get an api key
10
+
11
+ Scenario: Failed Login
12
+ Given I have a valid mailchimp account
13
+ When I attempt to login with incorrect credentials
14
+ Then I should get an error
15
+
16
+ Scenario: Add a key
17
+ Given I have a valid mailchimp account
18
+ And I have logged in
19
+ When I attempt to add an api key
20
+ Then I should be successful
21
+
@@ -0,0 +1,13 @@
1
+ Feature: Subscribe to a list
2
+ In order to send mass mailings in the future
3
+ As a developer
4
+ I want to subscribe given email addresses to a list
5
+ And I also want to potentially pass merge variables
6
+
7
+ Scenario: Email subscription
8
+ Given I have a valid mailchimp account
9
+ And a list named "Testing"
10
+ And I have logged in
11
+ When I attempt to subscribe "user@enlightsolutions.com" to the "Testing" list
12
+ Then the subscription should submit successfully
13
+
@@ -0,0 +1,14 @@
1
+ Feature: Unsubscription from a list
2
+ In order to comply with policies
3
+ And to provide a pleasurable experience for users
4
+ As a developer
5
+ I want to unsubscribe given email addresses from a list
6
+
7
+ Scenario: Email unsubscription
8
+ Given I have a valid mailchimp account
9
+ And a list named "Testing"
10
+ And I have logged in
11
+ And "user@enlightsolutions.com" is a subscriber to the "Testing" list
12
+ When I attempt to unsubscribe "user@enlightsolutions.com" from the "Testing" list
13
+ Then the unsubscription should be successful
14
+
@@ -0,0 +1,45 @@
1
+ Given /^I have a valid mailchimp account$/ do
2
+ assert_not_nil configatron.mailchimp.user_name
3
+ assert_not_nil configatron.mailchimp.password
4
+
5
+ @mailchimp_user_name = configatron.mailchimp.user_name
6
+ @mailchimp_password = configatron.mailchimp.password
7
+ end
8
+
9
+ When /^I attempt to login with the proper credentials$/ do
10
+ @account = MonkeyParty::Account.login(@mailchimp_user_name,
11
+ @mailchimp_password)
12
+ end
13
+
14
+ When /^I attempt to login with incorrect credentials$/ do
15
+ begin
16
+ @account = MonkeyParty::Account.login(@mailchimp_user_name,
17
+ "FAIL")
18
+ rescue MonkeyParty::Error => @exception
19
+ end
20
+ end
21
+
22
+ Then /^I should get an error$/ do
23
+ assert_not_nil @exception
24
+ end
25
+
26
+ Then /^I should get an api key$/ do
27
+ assert @account.keys.size == 1
28
+ end
29
+
30
+ Given /^I have logged in$/ do
31
+ @mailchimp_user_name = configatron.mailchimp.user_name
32
+ @mailchimp_password = configatron.mailchimp.password
33
+
34
+ @account = MonkeyParty::Account.login(@mailchimp_user_name,
35
+ @mailchimp_password)
36
+ end
37
+
38
+ When /^I attempt to add an api key$/ do
39
+ @additional_api_key = @account.add_api_key
40
+ end
41
+
42
+ Then /^I should be successful$/ do
43
+ assert @account.keys.include?(@additional_api_key)
44
+ end
45
+
@@ -0,0 +1,17 @@
1
+ Given /^a list named "([^\"]*)"$/ do |name|
2
+ assert_not_nil MonkeyParty::List.find_by_name(name)
3
+ end
4
+
5
+ When /^I attempt to subscribe "([^\"]*)" to the "([^\"]*)" list$/ do |email, list|
6
+ @subscribers = MonkeyParty::List.find_by_name(list).create_subscribers(
7
+ [MonkeyParty::Subscriber.new(email,
8
+ :first_name => "John",
9
+ :last_name => "Smith"
10
+ )], :update_existing => true, :double_optin => true)
11
+ end
12
+
13
+ Then /^the subscription should submit successfully$/ do
14
+ assert @subscribers[0].valid?
15
+ end
16
+
17
+
@@ -0,0 +1,17 @@
1
+ Given /^"([^\"]*)" is a subscriber to the "([^\"]*)" list$/ do |email, list|
2
+ @list = MonkeyParty::List.find_by_name(list)
3
+ @subscriber = MonkeyParty::Subscriber.new(email)
4
+ @subscriber = @list.create_subscribers([@subscriber],
5
+ :update_existing => true)[0]
6
+ assert @subscriber.valid?
7
+ end
8
+
9
+ When /^I attempt to unsubscribe "([^\"]*)" from the "([^\"]*)" list$/ do |email, list|
10
+ @subscriber = @list.destroy_subscribers([@subscriber],
11
+ :delete_member => true)[0]
12
+ end
13
+
14
+ Then /^the unsubscription should be successful$/ do
15
+ assert @subscriber.valid?
16
+ end
17
+
@@ -0,0 +1,4 @@
1
+ require 'test/unit/assertions'
2
+ require "monkey_party"
3
+
4
+ World(Test::Unit::Assertions)
@@ -0,0 +1,8 @@
1
+ #load account settings from a yaml file
2
+
3
+ require "configatron"
4
+ require "ruby-debug"
5
+
6
+ configatron.mailchimp.configure_from_yaml(
7
+ File.join(File.dirname(__FILE__), "account.yml"))
8
+
@@ -0,0 +1,2 @@
1
+ user_name: <user name>
2
+ password: <password>
@@ -0,0 +1,3 @@
1
+ #call in The Wolf to clean up after the party
2
+
3
+
@@ -0,0 +1,14 @@
1
+ require "rubygems"
2
+ require "httparty"
3
+ require "happymapper"
4
+
5
+ require "configatron"
6
+
7
+ require "monkey_party/error"
8
+
9
+ require "monkey_party/base"
10
+
11
+ require "monkey_party/subscriber"
12
+ require "monkey_party/account"
13
+ require "monkey_party/list"
14
+
@@ -0,0 +1,48 @@
1
+ module MonkeyParty
2
+ class Account < Base
3
+ attr_accessor :user_name, :password, :keys
4
+
5
+ def initialize(attrs = {})
6
+ self.keys ||= []
7
+ self.keys << attrs.delete(:api_key) if attrs[:api_key]
8
+ super
9
+ end
10
+
11
+ def api_key
12
+ self.keys[0]
13
+ end
14
+
15
+ class << self
16
+ def login(user_name, password)
17
+ response = get("", :query => {
18
+ :method => "login",
19
+ :username => user_name,
20
+ :password => password
21
+ })["MCAPI"]
22
+
23
+ account = new
24
+
25
+ account.keys << response
26
+ account.user_name = user_name
27
+ account.password = password
28
+
29
+ #set a global api key
30
+ configatron.mailchimp.api_key = response
31
+
32
+ account
33
+ end
34
+ end
35
+
36
+ def add_api_key
37
+ response = self.class.get("", :query => {
38
+ :method => "apikeyAdd",
39
+ :username => self.user_name,
40
+ :password => self.password,
41
+ :apikey => self.api_key
42
+ })["MCAPI"]
43
+
44
+ self.keys << response
45
+ response
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,30 @@
1
+ require "ruby-debug"
2
+ module MonkeyParty
3
+ class Base
4
+ include HTTParty
5
+ base_uri 'http://api.mailchimp.com/1.2/'
6
+ default_params :output => "xml"
7
+
8
+ def initialize(attrs = {})
9
+ attrs.each{ |key, value| self.send("#{key}=", value) }
10
+ end
11
+
12
+ class << self
13
+ def get(path, options = {})
14
+ #fix the format because Mail Chimp doesn't pass the proper header
15
+ options[:format] = :xml
16
+ result = super
17
+
18
+ if result.body =~ /<error /i
19
+ raise MonkeyParty::Error.parse(result.body)
20
+ end
21
+ result
22
+ end
23
+
24
+ def api_key
25
+ configatron.mailchimp.api_key
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ module MonkeyParty
2
+ class Error < Exception
3
+ include HappyMapper
4
+
5
+ tag 'MCAPI'
6
+ element :message, String, :tag => "error"
7
+ element :code, Integer
8
+ end
9
+ end
@@ -0,0 +1,99 @@
1
+ module MonkeyParty
2
+ class List < Base
3
+ include HappyMapper
4
+ tag "struct"
5
+
6
+ element :id, String
7
+ element :web_id, String
8
+ element :name, String
9
+ element :date_created, Time
10
+ element :member_count, Integer
11
+
12
+ def create_subscribers(array_of_subscribers, options = {})
13
+ options = {
14
+ :double_optin => true,
15
+ :update_existing => false,
16
+ :replace_interests => true
17
+ }.merge(options)
18
+
19
+ batch_hash = {}
20
+ index = 0
21
+ array_of_subscribers.each do |s|
22
+ batch_hash["batch[#{index}]"] = s.to_mailchimp_hash
23
+ index += 1
24
+ end
25
+
26
+ response = self.class.get("", :query => {
27
+ :apikey => self.class.api_key,
28
+ :id => self.id,
29
+ :method => "listBatchSubscribe",
30
+ }.merge(options).merge(batch_hash))
31
+
32
+ #response[1] is the error count
33
+ if !response["MCAPI"].nil? && response["MCAPI"][1] > 0
34
+ attach_errors_to_subscribers(array_of_subscribers, response.body)
35
+ end
36
+
37
+ array_of_subscribers
38
+ end
39
+
40
+ def destroy_subscribers(array_of_unsubscribers, options = {})
41
+ options = {
42
+ :delete_member => false,
43
+ :send_goodbye => true,
44
+ :send_notify => false
45
+ }.merge(options)
46
+
47
+ batch_hash = {}
48
+ index = 0
49
+ array_of_unsubscribers.each do |s|
50
+ batch_hash["emails[#{index}]"] = s.email
51
+ end
52
+
53
+ response = self.class.get("", :query => {
54
+ :apikey => self.class.api_key,
55
+ :id => self.id,
56
+ :method => "listBatchUnsubscribe"
57
+ }.merge(options).merge(batch_hash))
58
+
59
+ if !response["MCAPI"].nil? && response["MCAPI"][1] > 0
60
+ attach_errors_to_subscribers(array_of_unsubscribers, response.body)
61
+ end
62
+
63
+ array_of_unsubscribers
64
+ end
65
+
66
+ class << self
67
+ def all
68
+ response = get("", :query => {
69
+ :apikey => api_key,
70
+ :method => "lists"
71
+ })
72
+
73
+ parse(response.body)
74
+ end
75
+
76
+ def find_by_name(name)
77
+ all.each do |list|
78
+ return list if list.name.downcase == name.downcase
79
+ end
80
+
81
+ return nil
82
+ end
83
+ end
84
+
85
+ private
86
+ def attach_errors_to_subscribers(subscribers, response)
87
+ #parse errors and update subscriber
88
+ error_nodes = XML::Parser.string(response).parse.root.find("/MCAPI/errors/struct")
89
+ error_nodes.each do |n|
90
+
91
+ sub_error = MonkeyParty::Error.new
92
+ sub_error.message = n.find_first("message").content
93
+ sub_error.code = n.find_first("code").content
94
+
95
+ subscribers[n.attributes["key"].to_i].error = sub_error
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,30 @@
1
+ module MonkeyParty
2
+ class Subscriber
3
+ attr_accessor :email, :merge_fields, :error
4
+
5
+ def initialize(email, merge_fields = {})
6
+ self.email = email
7
+ self.merge_fields = merge_fields
8
+ self.error = nil
9
+ end
10
+
11
+ def to_h
12
+ {
13
+ :email => self.email
14
+ }.merge(self.merge_fields)
15
+ end
16
+
17
+ def to_mailchimp_hash
18
+ chimp_hash = {}
19
+ self.to_h.each do |key, value|
20
+ chimp_hash[key.to_s.upcase[0..9]] = value
21
+ end
22
+
23
+ chimp_hash
24
+ end
25
+
26
+ def valid?
27
+ self.error.nil?
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,87 @@
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{monkey_party}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dan Pickett"]
12
+ s.date = %q{2010-06-07}
13
+ s.email = %q{dpickett@enlightsolutions.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "features/create_and_add_api_key.feature",
25
+ "features/list_subscribe.feature",
26
+ "features/list_unsubscribe.feature",
27
+ "features/step_definitions/create_and_add_api_key_steps.rb",
28
+ "features/step_definitions/list_steps.rb",
29
+ "features/step_definitions/list_unsubscribe_steps.rb",
30
+ "features/support/env.rb",
31
+ "features/support/mailchimp/account.rb",
32
+ "features/support/mailchimp/account.yml.example",
33
+ "features/support/mailchimp/cleaner.rb",
34
+ "lib/monkey_party.rb",
35
+ "lib/monkey_party/account.rb",
36
+ "lib/monkey_party/base.rb",
37
+ "lib/monkey_party/error.rb",
38
+ "lib/monkey_party/list.rb",
39
+ "lib/monkey_party/subscriber.rb",
40
+ "monkey_party.gemspec",
41
+ "test/fixtures/batch_subscribe_failed.xml",
42
+ "test/fixtures/batch_subscribe_successful.xml",
43
+ "test/fixtures/batch_unsubscribe_failed.xml",
44
+ "test/fixtures/batch_unsubscribe_successful.xml",
45
+ "test/fixtures/lists_failed.xml",
46
+ "test/fixtures/lists_successful.xml",
47
+ "test/fixtures/login_failed.xml",
48
+ "test/fixtures/login_successful.xml",
49
+ "test/monkey_party/account_test.rb",
50
+ "test/monkey_party/error_test.rb",
51
+ "test/monkey_party/list_test.rb",
52
+ "test/monkey_party/subscriber_test.rb",
53
+ "test/test_helper.rb"
54
+ ]
55
+ s.homepage = %q{http://github.com/dpickett/monkey_party}
56
+ s.rdoc_options = ["--charset=UTF-8"]
57
+ s.require_paths = ["lib"]
58
+ s.rubygems_version = %q{1.3.7}
59
+ s.summary = %q{mailchimp wrapper}
60
+ s.test_files = [
61
+ "test/monkey_party/account_test.rb",
62
+ "test/monkey_party/error_test.rb",
63
+ "test/monkey_party/list_test.rb",
64
+ "test/monkey_party/subscriber_test.rb",
65
+ "test/test_helper.rb"
66
+ ]
67
+
68
+ if s.respond_to? :specification_version then
69
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
70
+ s.specification_version = 3
71
+
72
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
+ s.add_runtime_dependency(%q<httparty>, [">= 0.5.2"])
74
+ s.add_runtime_dependency(%q<happymapper>, [">= 0.3.0"])
75
+ s.add_runtime_dependency(%q<configatron>, [">= 2.6.3"])
76
+ else
77
+ s.add_dependency(%q<httparty>, [">= 0.5.2"])
78
+ s.add_dependency(%q<happymapper>, [">= 0.3.0"])
79
+ s.add_dependency(%q<configatron>, [">= 2.6.3"])
80
+ end
81
+ else
82
+ s.add_dependency(%q<httparty>, [">= 0.5.2"])
83
+ s.add_dependency(%q<happymapper>, [">= 0.3.0"])
84
+ s.add_dependency(%q<configatron>, [">= 2.6.3"])
85
+ end
86
+ end
87
+
@@ -0,0 +1,28 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="array">
8
+ <success_count type="integer">0</success_count>
9
+ <error_count type="integer">2</error_count>
10
+ <errors type="array">
11
+ <struct key="0" type="array">
12
+ <code type="integer">214</code>
13
+ <message type="string">user@example.com is already subscribed to list Testing</message>
14
+ <row type="array">
15
+ <EMAIL type="string">user@example.com</EMAIL>
16
+ </row>
17
+ </struct>
18
+ <struct key="1" type="array">
19
+
20
+ <code type="integer">214</code>
21
+ <message type="string">user@3example.com is already subscribed to list Testing</message>
22
+ <row type="array">
23
+ <EMAIL type="string">user@3example.com</EMAIL>
24
+ </row>
25
+ </struct>
26
+ </errors>
27
+ </MCAPI>
28
+
@@ -0,0 +1,12 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <mcapi type="array">
8
+ <success_count type="integer">2</success_count>
9
+ <error_count type="integer">0</error_count>
10
+ <errors type="array">
11
+ </errors></mcapi>
12
+
@@ -0,0 +1,19 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="array">
8
+ <success_count type="integer">0</success_count>
9
+ <error_count type="integer">1</error_count>
10
+ <errors type="array">
11
+ <struct key="0" type="array">
12
+ <code type="integer">232</code>
13
+ <message type="string">There is no record of &quot;user3@example.com&quot; in the database</message>
14
+ <email type="string">user3@example.com</email>
15
+ </struct>
16
+
17
+ </errors>
18
+ </MCAPI>
19
+
@@ -0,0 +1,12 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <mcapi type="array">
8
+ <success_count type="integer">1</success_count>
9
+ <error_count type="integer">0</error_count>
10
+ <errors type="array">
11
+ </errors></mcapi>
12
+
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="array">
8
+ <error type="string">Invalid Mailchimp API Key: fdasf</error>
9
+ <code type="integer">104</code>
10
+ </MCAPI>
11
+
@@ -0,0 +1,16 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="array">
8
+ <struct key="0" type="array">
9
+ <id type="string">d40bbc3056</id>
10
+ <web_id type="integer">63816</web_id>
11
+ <name type="string">Testing</name>
12
+ <date_created type="string">Mar 27, 2009 07:00 pm</date_created>
13
+ <member_count type="double">0</member_count>
14
+ </struct>
15
+ </MCAPI>
16
+
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="array">
8
+ <error type="string">I&apos;m sorry, that username/password could not be found</error>
9
+ <code type="integer">100</code>
10
+ </MCAPI>
11
+
@@ -0,0 +1,8 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 04 Feb 2009 03:42:26 GMT
3
+ Server: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch11
4
+ Content-Type: application/xml
5
+ Transfer-Encoding: chunked
6
+
7
+ <MCAPI type="string">2491541245g978jkasf</MCAPI>
8
+
@@ -0,0 +1,91 @@
1
+ require "test_helper"
2
+
3
+ class MonkeyParty::AccountTest < Test::Unit::TestCase
4
+ context "successfully logging in" do
5
+ setup do
6
+ configatron.mailchimp.api_key
7
+
8
+ mock_login_response(true)
9
+
10
+ @account = MonkeyParty::Account.login(@user_name, @password)
11
+ end
12
+
13
+ should "return an api key" do
14
+ assert_not_nil @account.api_key
15
+ end
16
+
17
+ should "set the user_name" do
18
+ assert_not_nil @account.user_name
19
+ end
20
+
21
+ should "set the global api key" do
22
+ assert_not_nil configatron.mailchimp.api_key
23
+ end
24
+ end
25
+
26
+ context "logging in with invalid credentials" do
27
+ setup do
28
+ mock_login_response(false)
29
+ end
30
+
31
+ should "raise an error" do
32
+ assert_raises MonkeyParty::Error do
33
+ MonkeyParty::Account.login(@user_name, @password)
34
+ end
35
+ end
36
+ end
37
+
38
+ context "adding an api key" do
39
+ setup do
40
+ @account = MonkeyParty::Account.new(
41
+ :user_name => "test",
42
+ :password => "password",
43
+ :api_key => "api_key")
44
+ end
45
+
46
+ context "with proper credentials" do
47
+ setup do
48
+ mock_response("password=#{@account.password}&" +
49
+ "apikey=#{@account.api_key}&method=apikeyAdd&" +
50
+ "output=xml&username=#{@account.user_name}",
51
+ "login_successful")
52
+ end
53
+
54
+ should "return an api key" do
55
+ response = @account.add_api_key
56
+ assert_kind_of String, response
57
+ end
58
+
59
+ should "add the resulting api key to extra keys" do
60
+ response = @account.add_api_key
61
+ assert @account.keys.include?(response)
62
+ end
63
+ end
64
+
65
+ context "with improper credentials" do
66
+ setup do
67
+ mock_response("password=#{@account.password}&" +
68
+ "apikey=#{@account.api_key}&method=apikeyAdd&" +
69
+ "output=xml&username=#{@account.user_name}",
70
+ "login_failed")
71
+ end
72
+
73
+ should "raise an error if I don't have the right credentials" do
74
+ assert_raise MonkeyParty::Error do
75
+ @account.add_api_key
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ private
82
+ def mock_login_response(successful = true)
83
+ @user_name = "test_user"
84
+ @password = "password"
85
+
86
+ mock_response("method=login&username=#{@user_name}" +
87
+ "&password=#{@password}&output=xml",
88
+ successful ? "login_successful" : "login_failed")
89
+
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ require "test_helper"
2
+
3
+ class MonkeyParty::ErrorTest < Test::Unit::TestCase
4
+ context "An error" do
5
+ setup do
6
+ error_body = File.read(xml_fixture_path("login_failed")).gsub(/.*<MCAPI/m, "<MCAPI")
7
+ @error = MonkeyParty::Error.parse(error_body)
8
+ end
9
+
10
+ should "have a code" do
11
+ assert_not_nil @error.code
12
+ end
13
+
14
+ should "have an error message" do
15
+ assert_not_nil @error.message
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,173 @@
1
+ require "test_helper"
2
+
3
+ class MonkeyParty::ListTest < Test::Unit::TestCase
4
+ context "a list" do
5
+ should "have a set of members" do
6
+
7
+ end
8
+
9
+ should "allow me to add members to the list" do
10
+ end
11
+
12
+ should "allow me to unsubscribe members from the list" do
13
+
14
+ end
15
+
16
+ should "have an id" do
17
+
18
+ end
19
+
20
+ should "have a web_id" do
21
+
22
+ end
23
+
24
+ should "have a name" do
25
+
26
+ end
27
+
28
+ should "have a date of creation" do
29
+
30
+ end
31
+
32
+ should "have a member count" do
33
+
34
+ end
35
+
36
+ end
37
+
38
+ context "when subscribing" do
39
+
40
+ setup do
41
+ mock_all_response
42
+
43
+ @list = MonkeyParty::List.all[0]
44
+
45
+ @subscribers = []
46
+ @subscribers << MonkeyParty::Subscriber.new("user@example.com",
47
+ {:fname => "A User"})
48
+ @subscribers << MonkeyParty::Subscriber.new("user3@example.com",
49
+ {:fname => "Another User"})
50
+
51
+
52
+ end
53
+
54
+ context "successfully" do
55
+ setup do
56
+ mock_subscription
57
+ @resultant_subscribers = @list.create_subscribers(@subscribers)
58
+ end
59
+
60
+ should "return an array of subscribers" do
61
+ assert_kind_of MonkeyParty::Subscriber, @resultant_subscribers[0]
62
+ end
63
+
64
+ should "indicate that each subscription was valid" do
65
+ @resultant_subscribers.each do |s|
66
+ assert s.valid?
67
+ end
68
+ end
69
+ end
70
+
71
+ context "resulting in error(s)" do
72
+ setup do
73
+ mock_subscription(false)
74
+ @resultant_subscribers = @list.create_subscribers(@subscribers)
75
+ end
76
+
77
+ should "have invalid subscribers" do
78
+ assert !@resultant_subscribers[0].valid?
79
+ end
80
+
81
+ should "have a subscriber with an error" do
82
+ assert_not_nil @resultant_subscribers[0].error
83
+ assert_kind_of MonkeyParty::Error, @resultant_subscribers[0].error
84
+ end
85
+ end
86
+ end
87
+
88
+ context "when unsubscribing" do
89
+ setup do
90
+ mock_all_response
91
+ @list = MonkeyParty::List.all[0]
92
+ @unsubscribers = [
93
+ MonkeyParty::Subscriber.new("user@example.com"),
94
+ MonkeyParty::Subscriber.new("user3@example.com")
95
+ ]
96
+ end
97
+
98
+ context "successfully" do
99
+ setup do
100
+ mock_unsubscription
101
+
102
+ @resultant_unsubscribers = @list.destroy_subscribers(@unsubscribers)
103
+ end
104
+
105
+ should "have all valid subscribers" do
106
+ @resultant_unsubscribers.each do |s|
107
+ assert s.valid?
108
+ end
109
+ end
110
+ end
111
+
112
+ context "resulting in errors(s)" do
113
+ setup do
114
+ mock_unsubscription(false)
115
+ @resultant_unsubscribers = @list.destroy_subscribers(@unsubscribers)
116
+ end
117
+
118
+ should "have an invalid subscriber" do
119
+ assert !@resultant_unsubscribers[0].valid?
120
+ end
121
+
122
+ should "have a usable error for the invalid subscriber" do
123
+ assert_not_nil @resultant_unsubscribers[0].error.message
124
+ end
125
+ end
126
+ end
127
+
128
+ context "lists" do
129
+ should "retrieving all of the lists" do
130
+ mock_all_response
131
+ lists = MonkeyParty::List.all
132
+ assert_kind_of Array, lists
133
+ assert_not_nil lists[0]
134
+ assert_not_nil lists[0].name
135
+ end
136
+
137
+ should "raise an error if something goes wrong" do
138
+ mock_all_response(false)
139
+ assert_raises MonkeyParty::Error do
140
+ lists = MonkeyParty::List.all
141
+ end
142
+ end
143
+
144
+ should "find by name" do
145
+ mock_all_response
146
+ assert_equal "Testing", MonkeyParty::List.find_by_name("Testing").name
147
+ end
148
+ end
149
+
150
+ private
151
+ def mock_all_response(success = true)
152
+ mock_response("apikey=2491541245g978jkasf&method=lists&output=xml",
153
+ success ? "lists_successful" : "lists_failed")
154
+ end
155
+
156
+ def mock_subscription(success = true)
157
+ mock_response(
158
+ "double_optin=true&update_existing=false&replace_interests=true&" +
159
+ "method=listBatchSubscribe&batch[1][EMAIL]=user3%40example.com&" +
160
+ "batch[1][FNAME]=Another%20User&output=xml&" +
161
+ "batch[0][EMAIL]=user%40example.com&batch[0][FNAME]=A%20User&"+
162
+ "apikey=2491541245g978jkasf&id=d40bbc3056",
163
+ success ? "batch_subscribe_successful" : "batch_subscribe_failed")
164
+ end
165
+
166
+ def mock_unsubscription(success = true)
167
+ mock_response(
168
+ "delete_member=false&send_goodbye=true&method=listBatchUnsubscribe&" +
169
+ "send_notify=false&output=xml&apikey=2491541245g978jkasf&id=d40bbc3056&" +
170
+ "emails[0]=user3%40example.com",
171
+ success ? "batch_unsubscribe_successful" : "batch_unsubscribe_failed")
172
+ end
173
+ end
@@ -0,0 +1,44 @@
1
+ require "test_helper"
2
+
3
+ class MonkeyParty::SubscriberTest < Test::Unit::TestCase
4
+ context "A subscriber" do
5
+ setup do
6
+ @merge_vars = {:merge_var => "MERGE VAR 1"}
7
+ @email = "user@example.com"
8
+ @subscriber = MonkeyParty::Subscriber.new(@email, @merge_vars)
9
+ end
10
+
11
+ should "have an email" do
12
+ assert_equal @email, @subscriber.email
13
+ end
14
+
15
+ should "have a list of merge fields" do
16
+ assert_equal @merge_vars, @subscriber.merge_fields
17
+ end
18
+
19
+ should "have a hashed version of all the attributes" do
20
+ intended_hash = {
21
+ :email => @email
22
+ }.merge(@merge_vars)
23
+
24
+ assert_equal intended_hash, @subscriber.to_h
25
+ end
26
+
27
+ should "have a mailchimp style hash of all the attributes" do
28
+ intended_hash = {}
29
+ intended_hash["EMAIL"] = @email
30
+ @merge_vars.each do |key, value|
31
+ intended_hash[key.to_s.upcase] = value
32
+ end
33
+
34
+ assert_equal intended_hash, @subscriber.to_mailchimp_hash
35
+ end
36
+
37
+ should "limit merge vars to 10 characters" do
38
+ @merge_vars = {:a_really_long_merge_var => "LONG ONE"}
39
+ @subscriber = MonkeyParty::Subscriber.new(@email, @merge_vars)
40
+ assert @subscriber.to_mailchimp_hash.keys.include?("A_REALLY_L")
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ begin
6
+ require "redgreen"
7
+ rescue LoadError; end
8
+
9
+ require 'fake_web'
10
+
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ require 'monkey_party'
14
+
15
+ FakeWeb.allow_net_connect = false
16
+
17
+ configatron.mailchimp.api_key = "api_key"
18
+
19
+ class Test::Unit::TestCase
20
+ protected
21
+ def mock_response(path, fixture)
22
+ FakeWeb.register_uri(
23
+ "http://api.mailchimp.com/1.2?#{path}",
24
+ :response => xml_fixture_path(fixture))
25
+ end
26
+
27
+ def xml_fixture_path(fixture)
28
+ File.join(File.dirname(__FILE__), "fixtures", "#{fixture}.xml")
29
+ end
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: monkey_party
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Dan Pickett
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-07 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: httparty
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 0
32
+ - 5
33
+ - 2
34
+ version: 0.5.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: happymapper
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 0
48
+ - 3
49
+ - 0
50
+ version: 0.3.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: configatron
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 17
62
+ segments:
63
+ - 2
64
+ - 6
65
+ - 3
66
+ version: 2.6.3
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ description:
70
+ email: dpickett@enlightsolutions.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files:
76
+ - LICENSE
77
+ - README.rdoc
78
+ files:
79
+ - .gitignore
80
+ - LICENSE
81
+ - README.rdoc
82
+ - Rakefile
83
+ - VERSION.yml
84
+ - features/create_and_add_api_key.feature
85
+ - features/list_subscribe.feature
86
+ - features/list_unsubscribe.feature
87
+ - features/step_definitions/create_and_add_api_key_steps.rb
88
+ - features/step_definitions/list_steps.rb
89
+ - features/step_definitions/list_unsubscribe_steps.rb
90
+ - features/support/env.rb
91
+ - features/support/mailchimp/account.rb
92
+ - features/support/mailchimp/account.yml.example
93
+ - features/support/mailchimp/cleaner.rb
94
+ - lib/monkey_party.rb
95
+ - lib/monkey_party/account.rb
96
+ - lib/monkey_party/base.rb
97
+ - lib/monkey_party/error.rb
98
+ - lib/monkey_party/list.rb
99
+ - lib/monkey_party/subscriber.rb
100
+ - monkey_party.gemspec
101
+ - test/fixtures/batch_subscribe_failed.xml
102
+ - test/fixtures/batch_subscribe_successful.xml
103
+ - test/fixtures/batch_unsubscribe_failed.xml
104
+ - test/fixtures/batch_unsubscribe_successful.xml
105
+ - test/fixtures/lists_failed.xml
106
+ - test/fixtures/lists_successful.xml
107
+ - test/fixtures/login_failed.xml
108
+ - test/fixtures/login_successful.xml
109
+ - test/monkey_party/account_test.rb
110
+ - test/monkey_party/error_test.rb
111
+ - test/monkey_party/list_test.rb
112
+ - test/monkey_party/subscriber_test.rb
113
+ - test/test_helper.rb
114
+ has_rdoc: true
115
+ homepage: http://github.com/dpickett/monkey_party
116
+ licenses: []
117
+
118
+ post_install_message:
119
+ rdoc_options:
120
+ - --charset=UTF-8
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ hash: 3
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ requirements: []
142
+
143
+ rubyforge_project:
144
+ rubygems_version: 1.3.7
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: mailchimp wrapper
148
+ test_files:
149
+ - test/monkey_party/account_test.rb
150
+ - test/monkey_party/error_test.rb
151
+ - test/monkey_party/list_test.rb
152
+ - test/monkey_party/subscriber_test.rb
153
+ - test/test_helper.rb