constant_contact 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +56 -0
  3. data/lib/constant_contact.rb +13 -0
  4. data/lib/constant_contact/activity.rb +41 -0
  5. data/lib/constant_contact/base.rb +150 -0
  6. data/lib/constant_contact/campaign.rb +112 -0
  7. data/lib/constant_contact/contact.rb +82 -0
  8. data/lib/constant_contact/contact_event.rb +7 -0
  9. data/lib/constant_contact/email_address.rb +6 -0
  10. data/lib/constant_contact/formats.rb +3 -0
  11. data/lib/constant_contact/formats/atom_format.rb +78 -0
  12. data/lib/constant_contact/formats/html_encoded_format.rb +17 -0
  13. data/lib/constant_contact/list.rb +11 -0
  14. data/lib/constant_contact/member.rb +5 -0
  15. data/lib/constant_contact/version.rb +3 -0
  16. data/test/constant_contact/activity_test.rb +41 -0
  17. data/test/constant_contact/atom_format_test.rb +28 -0
  18. data/test/constant_contact/base_test.rb +85 -0
  19. data/test/constant_contact/contact_test.rb +135 -0
  20. data/test/constant_contact/list_test.rb +17 -0
  21. data/test/constant_contact/member_test.rb +25 -0
  22. data/test/constant_contact_test.rb +8 -0
  23. data/test/fixtures/all_contacts.xml +51 -0
  24. data/test/fixtures/contactlistscollection.xml +96 -0
  25. data/test/fixtures/contactlistsindividuallist.xml +30 -0
  26. data/test/fixtures/memberscollection.xml +763 -0
  27. data/test/fixtures/new_list.xml +16 -0
  28. data/test/fixtures/nocontent.xml +12 -0
  29. data/test/fixtures/service_document.xml +15 -0
  30. data/test/fixtures/single_contact_by_email.xml +34 -0
  31. data/test/fixtures/single_contact_by_id.xml +71 -0
  32. data/test/fixtures/single_contact_by_id_with_no_contactlists.xml +65 -0
  33. data/test/test_helper.rb +46 -0
  34. metadata +186 -0
@@ -0,0 +1,7 @@
1
+ module ConstantContact
2
+ class ContactEvent < Base
3
+ self.site += "/contacts/:contact_id"
4
+ end
5
+ end
6
+
7
+
@@ -0,0 +1,6 @@
1
+ # http://developer.constantcontact.com/doc/settingsemails
2
+ module ConstantContact
3
+ class EmailAddress < Base
4
+ self.element_name = 'settings/emailaddresses'
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ directory = File.expand_path(File.dirname(__FILE__))
2
+ require File.join(directory, 'formats','atom_format')
3
+ require File.join(directory, 'formats','html_encoded_format')
@@ -0,0 +1,78 @@
1
+ require 'rexml/document'
2
+ module ActiveResource
3
+ module Formats
4
+ module AtomFormat
5
+ extend self
6
+
7
+ def extension
8
+ "atom"
9
+ end
10
+
11
+ def mime_type
12
+ "application/atom+xml"
13
+ end
14
+
15
+ def encode(hash, options={})
16
+ hash.to_xml(options)
17
+ end
18
+
19
+ def decode(xml)
20
+ return [] if no_content?(xml)
21
+ result = Hash.from_xml(from_atom_data(xml))
22
+ is_collection?(xml) ? result['records'] : result.values.first
23
+ end
24
+
25
+
26
+ private
27
+
28
+ def from_atom_data(xml)
29
+ if is_collection?(xml)
30
+ return content_from_collection(xml)
31
+ else
32
+ return content_from_single_record(xml)
33
+ end
34
+ end
35
+
36
+ def no_content?(xml)
37
+ doc = REXML::Document.new(xml)
38
+ REXML::XPath.match(doc,'//content').size == 0
39
+ end
40
+
41
+ def is_collection?(xml)
42
+ doc = REXML::Document.new(xml)
43
+ REXML::XPath.match(doc,'//content').size > 1
44
+ end
45
+
46
+ def content_from_single_record(xml)
47
+ doc = REXML::Document.new(xml)
48
+ str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
49
+ REXML::XPath.each(doc, '//content') do |e|
50
+ content = e.children[1]
51
+ str << content.to_s
52
+ end
53
+ str
54
+ end
55
+
56
+ def content_from_collection(xml)
57
+ doc = REXML::Document.new(xml)
58
+ str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><records type=\"array\">"
59
+ REXML::XPath.each(doc, '//content') do |e|
60
+ content = e.children[1]
61
+ str << content.to_s
62
+ end
63
+ str << "</records>"
64
+ str
65
+ end
66
+
67
+ def content_from_member(xml)
68
+ doc = REXML::Document.new(xml)
69
+ str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
70
+ REXML::XPath.each(doc, '//content') do |e|
71
+ content = e.children[1].children
72
+ str << content.to_s
73
+ end
74
+ str
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveResource
2
+ module Formats
3
+ module HtmlEncodedFormat
4
+ extend self
5
+ def mime_type
6
+ "application/x-www-form-urlencoded"
7
+ end
8
+
9
+
10
+ def decode(xml)
11
+ {}
12
+ end
13
+
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module ConstantContact
2
+ class List < Base
3
+
4
+ # @@column_names = [:contact_count, :display_on_signup, :members, :name, :opt_in_default, :short_name, :sort_order]
5
+
6
+ def self.find_by_name(name)
7
+ lists = self.find :all
8
+ lists.find{|list| list.Name == name}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module ConstantContact
2
+ class Member < Base
3
+ self.site += "/lists/:list_id"
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module ConstantContact
2
+ Version = '1.0.0'.freeze
3
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class Activity < Test::Unit::TestCase
4
+
5
+ context 'encode' do
6
+ setup do
7
+ @contacts = []
8
+ 3.times do |n|
9
+ @contacts << ConstantContact::Contact.new(:first_name => "Fred#{n}",
10
+ :last_name => "Test#{n}",
11
+ :email_address => "email#{n}@gmail.com")
12
+ end
13
+ @activity = ConstantContact::Activity.new(:activity_type => "SV_ADD")
14
+ @activity.contacts = @contacts
15
+ @list = ConstantContact::List.new
16
+ @list.stubs(:id).returns('http://api.constantcontact.com/ws/customers/joesflowers/lists/2')
17
+ @activity.lists = [@list]
18
+ end
19
+
20
+ should 'include activity type' do
21
+ assert_match(/activityType=SV_ADD/, @activity.encode)
22
+ end
23
+
24
+ should 'include contacts data' do
25
+ assert_match(/\&data\=Email\+Address\%2CFirst\+Name\%2CLast\+Name\%0A/, @activity.encode)
26
+ assert_match(/email0\%40gmail\.com\%2C\+Fred0\%2C\+Test0\%0A/, @activity.encode)
27
+ end
28
+
29
+ should 'include lists' do
30
+ assert_match(/Test2\&lists\=http\%3A\%2F\%2Fapi\.constantcontact\.com\%2Fws\%2Fcustomers\%2Fjoesflowers\%2Flists\%2F2/, @activity.encode)
31
+ end
32
+
33
+ end
34
+
35
+ context 'format' do
36
+ should 'be html encoded' do
37
+ assert_equal ActiveResource::Formats[:html_encoded], ConstantContact::Activity.connection.format
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class AtomFormatter
4
+ include ActiveResource::Formats::AtomFormat
5
+ end
6
+ class AtomFormatTest < Test::Unit::TestCase
7
+
8
+ context 'decode' do
9
+ should 'convert an xml collection into an array' do
10
+ c = AtomFormatter.new
11
+ assert_kind_of Array, c.decode(fixture_file('contactlistscollection.xml'))
12
+ end
13
+
14
+ should 'convert xml for a single record into a something' do
15
+ c = AtomFormatter.new
16
+ assert_kind_of Hash, c.decode(fixture_file('contactlistsindividuallist.xml'))
17
+ end
18
+
19
+ should 'return empty error if no content' do
20
+ c = AtomFormatter.new
21
+ assert_kind_of Array, c.decode(fixture_file('nocontent.xml'))
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ # require 'activeresource'
3
+ class BaseTest < Test::Unit::TestCase
4
+
5
+ # def test_should_use_site_prefix_and_credentials
6
+ # assert_equal 'https://baz%25foo:bar@api.constantcontact.com', ConstantContact::List.site.to_s
7
+ # end
8
+
9
+ def test_should_accept_setting_user
10
+ ConstantContact::List.api_key = 'api_key'
11
+ ConstantContact::List.user = 'david'
12
+ assert_equal('david', ConstantContact::List.user)
13
+ assert_equal('api_key%david', ConstantContact::List.connection.user)
14
+ end
15
+
16
+ def test_should_accept_setting_api_key
17
+ ConstantContact::List.api_key = 'david'
18
+ assert_equal('david', ConstantContact::List.api_key)
19
+ end
20
+
21
+
22
+ def test_should_accept_setting_password
23
+ ConstantContact::List.password = 'test123'
24
+ assert_equal('test123', ConstantContact::List.password)
25
+ assert_equal('test123', ConstantContact::List.connection.password)
26
+ end
27
+
28
+ def test_credentials_from_site_are_decoded
29
+ actor = Class.new(ConstantContact::Base)
30
+ actor.site = 'http://my%40email.com:%31%32%33@cinema'
31
+ assert_equal("my@email.com", actor.user)
32
+ assert_equal("123", actor.password)
33
+ end
34
+
35
+ def test_collection_name
36
+ assert_equal "lists", ConstantContact::List.collection_name
37
+ end
38
+
39
+ def test_collection_path
40
+ ConstantContact::Base.user = 'joesflowers'
41
+ assert_equal '/ws/customers/joesflowers/lists', ConstantContact::List.collection_path
42
+ end
43
+
44
+ def test_element_path
45
+ ConstantContact::Base.user = 'joesflowers'
46
+ assert_equal '/ws/customers/joesflowers/bases/1', ConstantContact::Base.element_path(1)
47
+ end
48
+
49
+ def test_should_use_site_prefix_and_credentials
50
+ ConstantContact::Base.user = "joesflowers"
51
+ ConstantContact::Base.password = "password"
52
+ ConstantContact::Base.api_key = "api_key"
53
+ assert_equal 'https://api.constantcontact.com/', ConstantContact::List.site.to_s
54
+ assert_equal 'https://api.constantcontact.com/lists/:list_id/', ConstantContact::Member.site.to_s
55
+ end
56
+
57
+
58
+ context 'find' do
59
+ setup do
60
+ ConstantContact::Base.user = "joesflowers"
61
+ ConstantContact::Base.password = "password"
62
+ ConstantContact::Base.api_key = "api_key"
63
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/lists', 'contactlistscollection.xml')
64
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/lists/1', 'contactlistsindividuallist.xml')
65
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/lists/1/members', 'memberscollection.xml')
66
+ end
67
+
68
+ should 'find one' do
69
+ list = ConstantContact::List.find(1)
70
+ assert_equal "General Interest", list.name
71
+ end
72
+
73
+ should 'find all' do
74
+ lists = ConstantContact::List.find(:all)
75
+ assert_equal 5, lists.size
76
+ assert_equal 'Clients', lists.last.name
77
+ end
78
+
79
+ should 'allow nested finds' do
80
+ members = ConstantContact::Member.find :all, :params => {:list_id => 1}
81
+ assert_equal 50, members.size
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,135 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ContactTest < Test::Unit::TestCase
4
+
5
+ context 'class' do
6
+ setup do
7
+ ConstantContact::Base.user = "jonsflowers"
8
+ @contact = ConstantContact::Contact.new(:email_address => "jon@example.com",
9
+ :first_name => "jon",
10
+ :last_name => "smith")
11
+ end
12
+
13
+ should 'respond to encode' do
14
+ assert_respond_to ConstantContact::Contact.new, :encode
15
+ end
16
+
17
+ should 'call to_xml' do
18
+ @contact.expects(:to_xml)
19
+ @contact.encode
20
+ end
21
+ end
22
+
23
+ context 'setting accessible attributes' do
24
+ setup do
25
+ ConstantContact::Base.user = "jonsflowers"
26
+ @contact = ConstantContact::Contact.new(:email_address => "jon@example.com",
27
+ :first_name => "jon",
28
+ :last_name => "smith")
29
+ end
30
+
31
+ should 'returns nil when contact list has not been set' do
32
+ assert_equal nil, @contact.contact_lists
33
+ end
34
+ should 'permit assigning ids to the contact list' do
35
+ @contact.contact_lists = [1,2]
36
+ assert_equal [1,2], @contact.contact_lists
37
+ end
38
+ end
39
+
40
+ context 'to_xml' do
41
+ setup do
42
+ ConstantContact::Base.user = "jonsflowers"
43
+ @contact = ConstantContact::Contact.new(:email_address => "jon@example.com",
44
+ :first_name => "jon",
45
+ :last_name => "smith")
46
+ end
47
+
48
+ should 'have contact tag' do
49
+ assert_match /<Contact xmlns=\"http:\/\/ws.constantcontact.com\/ns\/1.0\/\"/, @contact.to_xml
50
+ assert_match /\<\/Contact\>/, @contact.to_xml
51
+ end
52
+
53
+ should 'have first_name' do
54
+ assert_match /<FirstName>/, @contact.to_xml
55
+ end
56
+
57
+ should 'list selected by default' do
58
+ assert_match /http:\/\/api.constantcontact.com\/ws\/customers\/jonsflowers\/lists\/1/, @contact.to_xml
59
+ end
60
+
61
+ should 'provide opt in select by default' do
62
+ assert_match /ACTION_BY_CUSTOMER/, @contact.to_xml
63
+ end
64
+
65
+ should 'include the default contact list when no lists are specified' do
66
+ assert_match /<ContactList id="/, @contact.to_xml
67
+ end
68
+
69
+ should 'include all contact lists configured' do
70
+ @contact.contact_lists = [1,2]
71
+ assert_equal [1,2], @contact.contact_lists
72
+ xml = @contact.to_xml
73
+ assert_equal 2, xml.scan(/<ContactList /).length, xml
74
+ assert_match /<ContactList id="#{Regexp.escape(@contact.list_url(1))}"/, xml
75
+ assert_match /<ContactList id="#{Regexp.escape(@contact.list_url(2))}"/, xml
76
+ end
77
+ end
78
+
79
+ context "find with query parameters" do
80
+ setup do
81
+ ConstantContact::Base.user = "joesflowers"
82
+ ConstantContact::Base.password = "password"
83
+ ConstantContact::Base.api_key = "api_key"
84
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/contacts/2', 'single_contact_by_id.xml')
85
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/contacts/3', 'single_contact_by_id_with_no_contactlists.xml')
86
+ end
87
+
88
+ should 'find contact with given id' do
89
+ assert_equal 'jon smith', ConstantContact::Contact.find(2).Name
90
+ end
91
+
92
+ should 'return an array of lists they are a member of' do
93
+ c = ConstantContact::Contact.find(2)
94
+ assert_equal [1], c.contact_lists
95
+ end
96
+ should 'return an empty array when no contact lists are present' do
97
+ c = ConstantContact::Contact.find(3)
98
+ assert_equal [], c.contact_lists
99
+ end
100
+
101
+ end
102
+
103
+ context "find with email in query parameters" do
104
+ setup do
105
+ ConstantContact::Base.user = "joesflowers"
106
+ ConstantContact::Base.password = "password"
107
+ ConstantContact::Base.api_key = "api_key"
108
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/contacts', 'all_contacts.xml')
109
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/contacts?email=jon%40example.com', 'single_contact_by_email.xml')
110
+ end
111
+
112
+ should 'find contact with email address' do
113
+ assert_equal 'smith, jon', ConstantContact::Contact.find(:first, :params => {:email => 'jon@example.com'}).Name
114
+ end
115
+
116
+ should 'return nil when asking for contact_lists' do
117
+ assert_equal nil, ConstantContact::Contact.find(:first, :params => {:email => 'jon@example.com'}).contact_lists
118
+ end
119
+
120
+ end
121
+
122
+ context 'list url' do
123
+ setup do
124
+ ConstantContact::Base.user = "joesflowers"
125
+ end
126
+ should 'apply the default id (1) to a new contact' do
127
+ c = ConstantContact::Contact.new(:email_address => "jon@example.com",
128
+ :first_name => "jon",
129
+ :last_name => "smith")
130
+ assert_equal 'http://api.constantcontact.com/ws/customers/joesflowers/lists/1', c.list_url
131
+ assert_equal 'http://api.constantcontact.com/ws/customers/joesflowers/lists/2', c.list_url(2)
132
+ end
133
+ end
134
+
135
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ListTest < Test::Unit::TestCase
4
+
5
+ context "find by name" do
6
+ setup do
7
+ ConstantContact::List.user = "joesflowers"
8
+ ConstantContact::List.password = "password"
9
+ ConstantContact::List.api_key = "api_key"
10
+ stub_get('https://api_key%25joesflowers:password@api.constantcontact.com/ws/customers/joesflowers/lists', 'contactlistscollection.xml')
11
+ end
12
+
13
+ should 'find list for given name' do
14
+ assert_equal 'Clients', ConstantContact::List.find_by_name("Clients").name
15
+ end
16
+ end
17
+ end