constant_contact 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +56 -0
- data/lib/constant_contact.rb +13 -0
- data/lib/constant_contact/activity.rb +41 -0
- data/lib/constant_contact/base.rb +150 -0
- data/lib/constant_contact/campaign.rb +112 -0
- data/lib/constant_contact/contact.rb +82 -0
- data/lib/constant_contact/contact_event.rb +7 -0
- data/lib/constant_contact/email_address.rb +6 -0
- data/lib/constant_contact/formats.rb +3 -0
- data/lib/constant_contact/formats/atom_format.rb +78 -0
- data/lib/constant_contact/formats/html_encoded_format.rb +17 -0
- data/lib/constant_contact/list.rb +11 -0
- data/lib/constant_contact/member.rb +5 -0
- data/lib/constant_contact/version.rb +3 -0
- data/test/constant_contact/activity_test.rb +41 -0
- data/test/constant_contact/atom_format_test.rb +28 -0
- data/test/constant_contact/base_test.rb +85 -0
- data/test/constant_contact/contact_test.rb +135 -0
- data/test/constant_contact/list_test.rb +17 -0
- data/test/constant_contact/member_test.rb +25 -0
- data/test/constant_contact_test.rb +8 -0
- data/test/fixtures/all_contacts.xml +51 -0
- data/test/fixtures/contactlistscollection.xml +96 -0
- data/test/fixtures/contactlistsindividuallist.xml +30 -0
- data/test/fixtures/memberscollection.xml +763 -0
- data/test/fixtures/new_list.xml +16 -0
- data/test/fixtures/nocontent.xml +12 -0
- data/test/fixtures/service_document.xml +15 -0
- data/test/fixtures/single_contact_by_email.xml +34 -0
- data/test/fixtures/single_contact_by_id.xml +71 -0
- data/test/fixtures/single_contact_by_id_with_no_contactlists.xml +65 -0
- data/test/test_helper.rb +46 -0
- metadata +186 -0
@@ -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,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,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
|