monkey_party 0.2.0

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.
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