acts_as_icontact 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/acts_as_icontact.gemspec +12 -2
- data/lib/acts_as_icontact.rb +2 -0
- data/lib/acts_as_icontact/readonly.rb +21 -0
- data/lib/acts_as_icontact/resources/contact.rb +1 -1
- data/lib/acts_as_icontact/resources/contact_history.rb +4 -44
- data/lib/acts_as_icontact/resources/message.rb +22 -0
- data/lib/acts_as_icontact/resources/message_bounces.rb +16 -0
- data/lib/acts_as_icontact/resources/message_clicks.rb +16 -0
- data/lib/acts_as_icontact/resources/message_opens.rb +16 -0
- data/lib/acts_as_icontact/resources/message_statistics.rb +24 -0
- data/lib/acts_as_icontact/resources/segment.rb +35 -0
- data/lib/acts_as_icontact/resources/segment_criteria.rb +36 -0
- data/lib/acts_as_icontact/subresource.rb +54 -0
- data/spec/resources/account_spec.rb +0 -5
- data/spec/resources/clientfolder_spec.rb +1 -6
- data/spec/resources/contact_history_spec.rb +3 -3
- data/spec/resources/message_spec.rb +17 -0
- data/spec/resources/segment_spec.rb +31 -0
- data/spec/support/spec_fakeweb.rb +20 -1
- metadata +12 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.2
|
data/acts_as_icontact.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{acts_as_icontact}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Stephen Eley"]
|
12
|
-
s.date = %q{2009-08-
|
12
|
+
s.date = %q{2009-08-11}
|
13
13
|
s.default_executable = %q{icontact}
|
14
14
|
s.description = %q{ActsAsIcontact connects Ruby applications with the iContact e-mail marketing service using the iContact API v2.0. Building on the RestClient gem, it offers two significant feature sets:
|
15
15
|
|
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
"lib/acts_as_icontact/rails/lists.rb",
|
43
43
|
"lib/acts_as_icontact/rails/macro.rb",
|
44
44
|
"lib/acts_as_icontact/rails/mappings.rb",
|
45
|
+
"lib/acts_as_icontact/readonly.rb",
|
45
46
|
"lib/acts_as_icontact/resource.rb",
|
46
47
|
"lib/acts_as_icontact/resource_collection.rb",
|
47
48
|
"lib/acts_as_icontact/resources/account.rb",
|
@@ -52,7 +53,14 @@ Gem::Specification.new do |s|
|
|
52
53
|
"lib/acts_as_icontact/resources/custom_field.rb",
|
53
54
|
"lib/acts_as_icontact/resources/list.rb",
|
54
55
|
"lib/acts_as_icontact/resources/message.rb",
|
56
|
+
"lib/acts_as_icontact/resources/message_bounces.rb",
|
57
|
+
"lib/acts_as_icontact/resources/message_clicks.rb",
|
58
|
+
"lib/acts_as_icontact/resources/message_opens.rb",
|
59
|
+
"lib/acts_as_icontact/resources/message_statistics.rb",
|
60
|
+
"lib/acts_as_icontact/resources/segment.rb",
|
61
|
+
"lib/acts_as_icontact/resources/segment_criteria.rb",
|
55
62
|
"lib/acts_as_icontact/resources/subscription.rb",
|
63
|
+
"lib/acts_as_icontact/subresource.rb",
|
56
64
|
"rails/init.rb",
|
57
65
|
"spec/config_spec.rb",
|
58
66
|
"spec/connection_spec.rb",
|
@@ -70,6 +78,7 @@ Gem::Specification.new do |s|
|
|
70
78
|
"spec/resources/custom_field_spec.rb",
|
71
79
|
"spec/resources/list_spec.rb",
|
72
80
|
"spec/resources/message_spec.rb",
|
81
|
+
"spec/resources/segment_spec.rb",
|
73
82
|
"spec/resources/subscription_spec.rb",
|
74
83
|
"spec/spec.opts",
|
75
84
|
"spec/spec_helper.rb",
|
@@ -100,6 +109,7 @@ Gem::Specification.new do |s|
|
|
100
109
|
"spec/resources/custom_field_spec.rb",
|
101
110
|
"spec/resources/list_spec.rb",
|
102
111
|
"spec/resources/message_spec.rb",
|
112
|
+
"spec/resources/segment_spec.rb",
|
103
113
|
"spec/resources/subscription_spec.rb",
|
104
114
|
"spec/spec_helper.rb",
|
105
115
|
"spec/support/active_record/connection_adapters/nulldb_adapter.rb",
|
data/lib/acts_as_icontact.rb
CHANGED
@@ -7,6 +7,8 @@ require 'acts_as_icontact/config'
|
|
7
7
|
require 'acts_as_icontact/connection'
|
8
8
|
require 'acts_as_icontact/resource'
|
9
9
|
require 'acts_as_icontact/resource_collection'
|
10
|
+
require 'acts_as_icontact/subresource'
|
11
|
+
require 'acts_as_icontact/readonly'
|
10
12
|
|
11
13
|
# Load all of our resource files
|
12
14
|
Dir[File.join(File.dirname(__FILE__), 'acts_as_icontact', 'resources', '*.rb')].sort.each do |path|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
|
3
|
+
# Overrides methods to make a resource class read-only. Replaces property assignments and save methods with exceptions.
|
4
|
+
module ReadOnly
|
5
|
+
|
6
|
+
# Properties of this class are read-only.
|
7
|
+
def method_missing(method, *params)
|
8
|
+
raise ActsAsIcontact::ReadOnlyError, "#{self.class.readable_name} is read-only!" if method.to_s =~ /(.*)=$/
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Replace save methods with an exception
|
13
|
+
def cannot_save(*arguments)
|
14
|
+
raise ActsAsIcontact::ReadOnlyError, "Contact History is read-only!"
|
15
|
+
end
|
16
|
+
alias_method :save, :cannot_save
|
17
|
+
alias_method :save!, :cannot_save
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -25,7 +25,7 @@ module ActsAsIcontact
|
|
25
25
|
|
26
26
|
# Returns a collection of ContactHistory resources for this contact. The usual iContact search options (limit, offset, search terms, etc.) can be passed.
|
27
27
|
def history(options={})
|
28
|
-
ActsAsIcontact::ContactHistory.scoped_find(self, options)
|
28
|
+
@history ||= ActsAsIcontact::ContactHistory.scoped_find(self, options)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -2,51 +2,11 @@ module ActsAsIcontact
|
|
2
2
|
# The read-only list of actions attached to every Contact. Because of this intrinsic association, the usual #find methods don't
|
3
3
|
# work; contact history _must_ be obtained using the individual contact's #history method.
|
4
4
|
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
5
|
-
class ContactHistory <
|
6
|
-
|
7
|
-
alias_method :contact, :parent
|
8
|
-
|
9
|
-
# Should only be called by ResourceCollection. Raises an exception if a parent object is not passed.
|
10
|
-
def initialize(properties={})
|
11
|
-
@parent = properties.delete(:parent) or raise ActsAsIcontact::ValidationError, "Contact History requires a Contact"
|
12
|
-
super
|
13
|
-
end
|
14
|
-
|
15
|
-
# Properties of this class are read-only.
|
16
|
-
def method_missing(method, *params)
|
17
|
-
raise ActsAsIcontact::ReadOnlyError, "Contact History is read-only!" if method.to_s =~ /(.*)=$/
|
18
|
-
super
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
# Returns the ContactHistory collection for the passed contact. Takes the usual iContact search parameters.
|
23
|
-
def self.scoped_find(parent, options = {})
|
24
|
-
query_options = default_options.merge(options)
|
25
|
-
validate_options(query_options)
|
26
|
-
uri_extension = uri_component + build_query(query_options)
|
27
|
-
response = parent.connection[uri_extension].get
|
28
|
-
parsed = JSON.parse(response)
|
29
|
-
ResourceCollection.new(self, parsed, :parent => parent)
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
class <<self
|
34
|
-
# Replace all search methods with an exception
|
35
|
-
def cannot_query(*arguments)
|
36
|
-
raise ActsAsIcontact::QueryError, "Contact History must be obtained using the contact.history method."
|
37
|
-
end
|
38
|
-
alias_method :all, :cannot_query
|
39
|
-
alias_method :first, :cannot_query
|
40
|
-
alias_method :find, :cannot_query
|
41
|
-
end
|
42
|
-
|
43
|
-
# Replace save methods with an exception
|
44
|
-
def cannot_save(*arguments)
|
45
|
-
raise ActsAsIcontact::ReadOnlyError, "Contact History is read-only!"
|
46
|
-
end
|
47
|
-
alias_method :save, :cannot_save
|
48
|
-
alias_method :save!, :cannot_save
|
5
|
+
class ContactHistory < Subresource
|
6
|
+
include ReadOnly
|
49
7
|
|
8
|
+
alias_method :contact, :parent
|
9
|
+
|
50
10
|
protected
|
51
11
|
# An oddball resource class; iContact's URL for it is 'actions', not 'contact_histories'.
|
52
12
|
def self.resource_name
|
@@ -24,5 +24,27 @@ module ActsAsIcontact
|
|
24
24
|
nil
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
# Returns a collection of MessageBounces resources for this message. The usual iContact search options (limit, offset, search terms, etc.) can be passed.
|
29
|
+
def bounces(options={})
|
30
|
+
@bounces ||= ActsAsIcontact::MessageBounces.scoped_find(self, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a collection of MessageClicks resources for this message. The usual iContact search options (limit, offset, search terms, etc.) can be passed.
|
34
|
+
def clicks(options={})
|
35
|
+
@clicks ||= ActsAsIcontact::MessageClicks.scoped_find(self, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a collection of MessageOpens resources for this message. The usual iContact search options (limit, offset, search terms, etc.) can be passed.
|
39
|
+
def opens(options={})
|
40
|
+
@opens ||= ActsAsIcontact::MessageOpens.scoped_find(self, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the Statistics record for this contact. This is a singleton resource and does not accept find, etc.
|
44
|
+
def statistics(options={})
|
45
|
+
@statistics ||= ActsAsIcontact::MessageStatistics.scoped_first(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
27
49
|
end
|
28
50
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The read-only list of bounces attached to every Message. Because of this intrinsic association, the usual #find methods don't
|
3
|
+
# work; this collectin _must_ be obtained using the individual message's #bounces method.
|
4
|
+
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
5
|
+
class MessageBounces < Subresource
|
6
|
+
include ReadOnly
|
7
|
+
|
8
|
+
alias_method :message, :parent
|
9
|
+
|
10
|
+
# Retrieves the contact pointed to by this message record's contactId.
|
11
|
+
def contact
|
12
|
+
@contact ||= ActsAsIcontact::Contact.find(contactId.to_i) if contactId.to_i > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The read-only list of clicks attached to every Message. Because of this intrinsic association, the usual #find methods don't
|
3
|
+
# work; this collection _must_ be obtained using the individual message's #clicks method.
|
4
|
+
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
5
|
+
class MessageClicks < Subresource
|
6
|
+
include ReadOnly
|
7
|
+
|
8
|
+
alias_method :message, :parent
|
9
|
+
|
10
|
+
# Retrieves the contact pointed to by this message record's contactId.
|
11
|
+
def contact
|
12
|
+
@contact ||= ActsAsIcontact::Contact.find(contactId.to_i) if contactId.to_i > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The read-only list of opens attached to every Message. Because of this intrinsic association, the usual #find methods don't
|
3
|
+
# work; this collection _must_ be obtained using the individual message's #opens method.
|
4
|
+
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
5
|
+
class MessageOpens < Subresource
|
6
|
+
include ReadOnly
|
7
|
+
|
8
|
+
alias_method :message, :parent
|
9
|
+
|
10
|
+
# Retrieves the contact pointed to by this message record's contactId.
|
11
|
+
def contact
|
12
|
+
@contact ||= ActsAsIcontact::Contact.find(contactId.to_i) if contactId.to_i > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The read-only set of statistics attached to every Message. Because of this intrinsic association, the usual #find methods don't
|
3
|
+
# work; this resource _must_ be obtained using the individual message's #statistics method. Note also that
|
4
|
+
# this is a singleton resource, _not_ a collection.
|
5
|
+
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
6
|
+
class MessageStatistics < Subresource
|
7
|
+
include ReadOnly
|
8
|
+
|
9
|
+
alias_method :message, :parent
|
10
|
+
|
11
|
+
# This one's a little weird; remove scoped_find, and add scoped_first to retrieve just one record
|
12
|
+
class <<self
|
13
|
+
alias_method :scoped_find, :cannot_query
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns just one resource corresponding to the parent Message
|
17
|
+
def self.scoped_first(parent)
|
18
|
+
response = parent.connection[collection_name].get
|
19
|
+
parsed = JSON.parse(response)
|
20
|
+
self.new(parsed[collection_name].merge(:parent => parent))
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
class Segment < Resource
|
3
|
+
|
4
|
+
# Name and listId are required
|
5
|
+
def self.required_on_create
|
6
|
+
super << 'listId' << 'name'
|
7
|
+
end
|
8
|
+
|
9
|
+
# Name and listId are required
|
10
|
+
def self.required_on_update
|
11
|
+
super << 'name'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Cannot pass listId when updating
|
15
|
+
def self.never_on_update
|
16
|
+
['listId']
|
17
|
+
end
|
18
|
+
|
19
|
+
# Searches on segment name.
|
20
|
+
def self.find_by_string(value)
|
21
|
+
first(:name => value)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Returns the list to which this segment is bound.
|
26
|
+
def list
|
27
|
+
@list ||= ActsAsIcontact::List.find(listId.to_i) if (listId.to_i) > 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a collection of SegmentCriteria resources for this segment. The usual iContact search options (limit, offset, search terms, etc.) can be passed.
|
31
|
+
def criteria(options={})
|
32
|
+
@criteria ||= ActsAsIcontact::SegmentCriteria.scoped_find(self, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The list of criteria attached to every Segment. Because of this intrinsic association, the usual #find methods don't
|
3
|
+
# work; this collection _must_ be obtained using the individual segment's #criteria method.
|
4
|
+
# Unlike other subresources, SegmentCriteria can be created, modified, and saved.
|
5
|
+
class SegmentCriteria < Subresource
|
6
|
+
|
7
|
+
alias_method :segment, :parent
|
8
|
+
|
9
|
+
# fieldName, operator, and values are required
|
10
|
+
def self.required_on_create
|
11
|
+
super + %w(fieldName operator values)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Looks like 'criteria' is just a bit too strange for ActiveSupport to know singulars and plurals...
|
15
|
+
def self.resource_name # :nodoc:
|
16
|
+
"criterion"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.collection_name # :nodoc:
|
20
|
+
"criteria"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Uses criterionId as its ID.
|
24
|
+
def id
|
25
|
+
properties["criterionId"]
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# operator must be one: eq, lt, lte, gt, gte, bet, notcontains, contains
|
30
|
+
def validate_on_save(fields)
|
31
|
+
operators = %w(eq lt lte gt gte bet notcontains contains)
|
32
|
+
raise ActsAsIcontact::ValidationError, "operator must be one of: " + operators.join(', ') unless operators.include?(fields["operator"])
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# A read-only resource placed beneath the URL of another resource and containing secondary information.
|
3
|
+
# Because of this intrinsic association, the usual #find methods don't
|
4
|
+
# work; subresources _must_ be obtained using an association method from the parent resource.
|
5
|
+
# Property updates and saving are also prohibited (returning a ReadOnlyError exception.)
|
6
|
+
class Subresource < Resource
|
7
|
+
attr_reader :parent
|
8
|
+
|
9
|
+
# Should only be called by ResourceCollection. Raises an exception if a parent object is not passed.
|
10
|
+
def initialize(properties={})
|
11
|
+
@parent = properties.delete(:parent) or raise ActsAsIcontact::ValidationError, "#{self.class.readable_name} requires a #{self.class.readable_parent}"
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Returns the ContactHistory collection for the passed contact. Takes the usual iContact search parameters.
|
17
|
+
def self.scoped_find(parent, options = {})
|
18
|
+
query_options = default_options.merge(options)
|
19
|
+
validate_options(query_options)
|
20
|
+
uri_extension = uri_component + build_query(query_options)
|
21
|
+
response = parent.connection[uri_extension].get
|
22
|
+
parsed = JSON.parse(response)
|
23
|
+
ResourceCollection.new(self, parsed, :parent => parent)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class <<self
|
28
|
+
# Replace all search methods with an exception
|
29
|
+
def cannot_query(*arguments)
|
30
|
+
raise ActsAsIcontact::QueryError, "#{readable_name} must be obtained using the #{readable_parent}\##{parent_method} method."
|
31
|
+
end
|
32
|
+
alias_method :all, :cannot_query
|
33
|
+
alias_method :first, :cannot_query
|
34
|
+
alias_method :find, :cannot_query
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
def self.resource_name
|
39
|
+
parent_method.singularize
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.readable_name
|
43
|
+
name.demodulize.titleize
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.readable_parent
|
47
|
+
readable_name.split[0]
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.parent_method
|
51
|
+
readable_name.split[1].downcase
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -21,11 +21,6 @@ describe ActsAsIcontact, "account method" do
|
|
21
21
|
ActsAsIcontact.account.should be_a_kind_of(RestClient::Resource)
|
22
22
|
end
|
23
23
|
|
24
|
-
it "builds upon the 'connection' object" do
|
25
|
-
ActsAsIcontact.expects(:connection).returns(ActsAsIcontact.instance_variable_get(:@connection))
|
26
|
-
ActsAsIcontact.account.should_not be_nil
|
27
|
-
end
|
28
|
-
|
29
24
|
it "can be cleared with the reset_account! method" do
|
30
25
|
ActsAsIcontact.reset_account!
|
31
26
|
ActsAsIcontact.instance_variable_get(:@account).should be_nil
|
@@ -20,12 +20,7 @@ describe ActsAsIcontact, "clientfolder method" do
|
|
20
20
|
it "returns a RestClient resource" do
|
21
21
|
ActsAsIcontact.clientfolder.should be_a_kind_of(RestClient::Resource)
|
22
22
|
end
|
23
|
-
|
24
|
-
it "builds upon the 'account' object" do
|
25
|
-
ActsAsIcontact.expects(:account).returns(ActsAsIcontact.instance_variable_get(:@account))
|
26
|
-
ActsAsIcontact.clientfolder.should_not be_nil
|
27
|
-
end
|
28
|
-
|
23
|
+
|
29
24
|
it "can be cleared with the reset_account! method" do
|
30
25
|
ActsAsIcontact.reset_clientfolder!
|
31
26
|
ActsAsIcontact.instance_variable_get(:@clientfolder).should be_nil
|
@@ -19,15 +19,15 @@ describe ActsAsIcontact::ContactHistory do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it "does not allow .find" do
|
22
|
-
lambda{ActsAsIcontact::ContactHistory.find(:all)}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the
|
22
|
+
lambda{ActsAsIcontact::ContactHistory.find(:all)}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the Contact#history method.")
|
23
23
|
end
|
24
24
|
|
25
25
|
it "does not allow .first" do
|
26
|
-
lambda{ActsAsIcontact::ContactHistory.first}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the
|
26
|
+
lambda{ActsAsIcontact::ContactHistory.first}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the Contact#history method.")
|
27
27
|
end
|
28
28
|
|
29
29
|
it "does not allow .all" do
|
30
|
-
lambda{ActsAsIcontact::ContactHistory.all}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the
|
30
|
+
lambda{ActsAsIcontact::ContactHistory.all}.should raise_error(ActsAsIcontact::QueryError, "Contact History must be obtained using the Contact#history method.")
|
31
31
|
end
|
32
32
|
|
33
33
|
it "requires a contactId" do
|
@@ -25,6 +25,23 @@ describe ActsAsIcontact::Message do
|
|
25
25
|
it "knows which campaign it has (if any)" do
|
26
26
|
@message.campaign.name.should == "Test Campaign"
|
27
27
|
end
|
28
|
+
|
29
|
+
it "knows its bounces" do
|
30
|
+
@message.bounces.first.contact.email.should == "john@example.org"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "knows its clicks" do
|
34
|
+
@message.clicks.first.clickLink.should == "http://www.yahoo.com"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "knows its opens" do
|
38
|
+
@message.opens.first.contact.email.should == "john@example.org"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "knows its statistics" do
|
42
|
+
@message.statistics.delivered.should == 3
|
43
|
+
end
|
44
|
+
|
28
45
|
end
|
29
46
|
|
30
47
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact::Segment do
|
4
|
+
|
5
|
+
|
6
|
+
it "requires a listId" do
|
7
|
+
s = ActsAsIcontact::Segment.new
|
8
|
+
lambda{s.save}.should raise_error(ActsAsIcontact::ValidationError, /listId/)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "requires a name" do
|
12
|
+
s = ActsAsIcontact::Segment.new
|
13
|
+
lambda{s.save}.should raise_error(ActsAsIcontact::ValidationError, /name/)
|
14
|
+
end
|
15
|
+
|
16
|
+
context "associations" do
|
17
|
+
# We have _one_ really good segment set up here
|
18
|
+
before(:each) do
|
19
|
+
@segment = ActsAsIcontact::Segment.find("People Named John")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "knows its list" do
|
23
|
+
@segment.list.name.should == "First Test"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "knows its criteria" do
|
27
|
+
@segment.criteria.first.fieldName.should == "firstName"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -53,6 +53,19 @@ FakeWeb.register_uri(:get, "#{ic}/messages?limit=500&campaignId=777777&messageTy
|
|
53
53
|
#### Test message for associations originating from Message spec
|
54
54
|
FakeWeb.register_uri(:get, "#{ic}/messages?limit=1&subject=Test%20Message", :body => %q<{"messages":[{"messageId":"666666","subject":"Test Message","messageType":"normal","textBody":"Hi there!\nThis is just a test.","htmlBody":"<p><b>Hi there!</b></p><p>This is just a <i>test.</i></p>","createDate":"20090725 14:53:33","campaignId":"777777"}]}>)
|
55
55
|
|
56
|
+
# Message Bounces
|
57
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/666666/bounces?limit=500", :body => %q<{"bounces":[{"contactId":"333333","bounceTime":"2008-04-15T12:05:00-04:00"},{"contactId":"333333","bounceTime":"2008-04-16T12:05:00-04:00"}],"total":2,"limit":500,"offset":0}>)
|
58
|
+
|
59
|
+
# Message Clicks
|
60
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/666666/clicks?limit=500", :body => %q<{"clicks":[{"contactId":"333333","clickTime":"2008-04-17T12:07:00-04:00","clickLink":"http://www.yahoo.com"},{"contactId":"333333","clickTime":"2008-04-17T12:07:30-04:00","clickLink":"http://google.com"}],"total":2,"limit":500,"offset":0}>)
|
61
|
+
|
62
|
+
# Message Opens
|
63
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/666666/opens?limit=500", :body => %q<{"opens":[{"contactId":"333333","openTime":"2008-04-17T12:06:00-04:00"},{"contactId":"333444","bounceTime":"2008-04-17T12:06:15-04:00"}],"total":2,"limit":500,"offset":0}>)
|
64
|
+
|
65
|
+
# Message Statistics
|
66
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/666666/statistics", :body => %q<{"statistics":{"bounces":2,"delivered":3,"unsubscribes":0,"opens":{"unique":2,"total":2},"clicks":{"unique":2,"total":2},"forwards":0,"comments":0,"complaints":0}}>)
|
67
|
+
|
68
|
+
|
56
69
|
# CustomField
|
57
70
|
FakeWeb.register_uri(:get, "#{ic}/customfields?limit=500", :body => %q<{"customfields":[{"privateName":"test_field","publicName":"Test Field","displayToUser":"0","fieldType":"text"},{"privateName":"custom_field","publicName":"This is for the Rails integration specs","displayToUser":1,"fieldType":"text"}],"total":2}>)
|
58
71
|
FakeWeb.register_uri(:get, "#{ic}/customfields/test_field", :body => %q<{"customfield":{"privateName":"test_field","publicName":"Test Field","displayToUser":"0","fieldType":"text"}}>)
|
@@ -69,4 +82,10 @@ FakeWeb.register_uri(:post, "#{ic}/subscriptions", :body => %q<{"subscriptions":
|
|
69
82
|
|
70
83
|
# Campaign
|
71
84
|
FakeWeb.register_uri(:get, "#{ic}/campaigns?limit=1", :body => %q<{"campaigns":[{"campaignId":"777777","name":"Test Campaign","fromName":"Bob Smith","fromEmail":"bob@example.org","forwardToFriend":0,"subscriptionManagement":1,"clickTrackMode":1,"useAccountAddress":0,"archiveByDefault":0,"description":""}],"count":1}>)
|
72
|
-
FakeWeb.register_uri(:get, "#{ic}/campaigns/777777", :body => %q<{"campaign":{"campaignId":"777777","name":"Test Campaign","fromName":"Bob Smith","fromEmail":"bob@example.org","forwardToFriend":0,"subscriptionManagement":1,"clickTrackMode":1,"useAccountAddress":0,"archiveByDefault":0,"description":""}}>)
|
85
|
+
FakeWeb.register_uri(:get, "#{ic}/campaigns/777777", :body => %q<{"campaign":{"campaignId":"777777","name":"Test Campaign","fromName":"Bob Smith","fromEmail":"bob@example.org","forwardToFriend":0,"subscriptionManagement":1,"clickTrackMode":1,"useAccountAddress":0,"archiveByDefault":0,"description":""}}>)
|
86
|
+
|
87
|
+
# Segment
|
88
|
+
FakeWeb.register_uri(:get, "#{ic}/segments?limit=1&name=People%20Named%20John", :body => %q<{"segments":[{"segmentId":"888888","listId":"444444","name":"People Named John","description":"All the people named John"}],"total":1,"limit":1,"offset":1}>)
|
89
|
+
|
90
|
+
# Segment Criteria
|
91
|
+
FakeWeb.register_uri(:get, "#{ic}/segments/888888/criteria?limit=500", :body => %q<{"criteria":[{"criterionId":0,"fieldName":"firstName","operator":"eq","values":["John"]}]}>)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_icontact
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Eley
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-11 00:00:00 -04:00
|
13
13
|
default_executable: icontact
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/acts_as_icontact/rails/lists.rb
|
107
107
|
- lib/acts_as_icontact/rails/macro.rb
|
108
108
|
- lib/acts_as_icontact/rails/mappings.rb
|
109
|
+
- lib/acts_as_icontact/readonly.rb
|
109
110
|
- lib/acts_as_icontact/resource.rb
|
110
111
|
- lib/acts_as_icontact/resource_collection.rb
|
111
112
|
- lib/acts_as_icontact/resources/account.rb
|
@@ -116,7 +117,14 @@ files:
|
|
116
117
|
- lib/acts_as_icontact/resources/custom_field.rb
|
117
118
|
- lib/acts_as_icontact/resources/list.rb
|
118
119
|
- lib/acts_as_icontact/resources/message.rb
|
120
|
+
- lib/acts_as_icontact/resources/message_bounces.rb
|
121
|
+
- lib/acts_as_icontact/resources/message_clicks.rb
|
122
|
+
- lib/acts_as_icontact/resources/message_opens.rb
|
123
|
+
- lib/acts_as_icontact/resources/message_statistics.rb
|
124
|
+
- lib/acts_as_icontact/resources/segment.rb
|
125
|
+
- lib/acts_as_icontact/resources/segment_criteria.rb
|
119
126
|
- lib/acts_as_icontact/resources/subscription.rb
|
127
|
+
- lib/acts_as_icontact/subresource.rb
|
120
128
|
- rails/init.rb
|
121
129
|
- spec/config_spec.rb
|
122
130
|
- spec/connection_spec.rb
|
@@ -134,6 +142,7 @@ files:
|
|
134
142
|
- spec/resources/custom_field_spec.rb
|
135
143
|
- spec/resources/list_spec.rb
|
136
144
|
- spec/resources/message_spec.rb
|
145
|
+
- spec/resources/segment_spec.rb
|
137
146
|
- spec/resources/subscription_spec.rb
|
138
147
|
- spec/spec.opts
|
139
148
|
- spec/spec_helper.rb
|
@@ -186,6 +195,7 @@ test_files:
|
|
186
195
|
- spec/resources/custom_field_spec.rb
|
187
196
|
- spec/resources/list_spec.rb
|
188
197
|
- spec/resources/message_spec.rb
|
198
|
+
- spec/resources/segment_spec.rb
|
189
199
|
- spec/resources/subscription_spec.rb
|
190
200
|
- spec/spec_helper.rb
|
191
201
|
- spec/support/active_record/connection_adapters/nulldb_adapter.rb
|