createsend 0.0.1 → 0.0.2

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.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 James Dennes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,3 +1,65 @@
1
1
  # createsend
2
2
 
3
- A wrapper for the createsend API v3.
3
+ A ruby library which implements the complete functionality of v3 of the CreateSend API.
4
+
5
+ ## Installation
6
+
7
+ sudo gem install createsend
8
+
9
+ ## Examples
10
+
11
+ ### Basic usage
12
+ Retrieve a list of all your clients.
13
+
14
+ require 'createsend'
15
+
16
+ CreateSend.api_key 'your_api_key'
17
+
18
+ cs = CreateSend.new
19
+ clients = cs.clients
20
+
21
+ clients.each do |c|
22
+ puts "#{c.ClientID}: #{c.Name}"
23
+ end
24
+
25
+ Results in:
26
+
27
+ 4a397ccaaa55eb4e6aa1221e1e2d7122: Client One
28
+ a206def0582eec7dae47d937a4109cb2: Client Two
29
+
30
+ ### Handling errors
31
+ If the createsend API returns an error, an exception will be thrown. For example, if you attempt to create a campaign and enter empty values for subject etc:
32
+
33
+ require 'createsend'
34
+
35
+ CreateSend.api_key 'your_api_key'
36
+
37
+ begin
38
+ cl = Client.new "4a397ccaaa55eb4e6aa1221e1e2d7122"
39
+ id = Campaign.create cl.client_id, "", "", "", "", "", "", "", [], []
40
+ puts "New campaign ID: #{id}"
41
+ rescue BadRequest => br
42
+ puts "Bad request error: #{br}"
43
+ puts "Error Code: #{br.data.Code}"
44
+ puts "Error Message: #{br.data.Message}"
45
+ rescue Exception => e
46
+ puts "Error: #{e}"
47
+ end
48
+
49
+ Results in:
50
+
51
+ Bad request error: The CreateSend API responded with the following error - 304: Campaign Subject Required
52
+ Error Code: 304
53
+ Error Message: Campaign Subject Required
54
+
55
+ ### Expected input and output
56
+ The best way of finding out the expected input and output of a particular method in a particular class is to use the unit tests as a reference.
57
+
58
+ For example, if you wanted to find out how to call the Subscriber.add method, you would look at the file test/subscriber_test.rb
59
+
60
+ should "add a subscriber with custom fields" do
61
+ stub_post(@api_key, "subscribers/#{@list_id}.json", "add_subscriber.json")
62
+ custom_fields = [ { :Key => 'website', :Value => 'http://example.com/' } ]
63
+ email_address = Subscriber.add @list_id, "subscriber@example.com", "Subscriber", custom_fields, true
64
+ email_address.should == "subscriber@example.com"
65
+ end
@@ -12,13 +12,13 @@ Gem::Specification.new do |s|
12
12
  s.add_runtime_dependency('httparty', '~> 0.6.1')
13
13
  s.name = "createsend"
14
14
  s.author = "James Dennes"
15
- s.description = %q{A wrapper for the CreateSend API v3}
15
+ s.description = %q{A library which implements the complete functionality of v3 of the createsend API.}
16
16
  s.email = ["jdennes@gmail.com"]
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
18
18
  s.files = `git ls-files`.split("\n")
19
19
  s.homepage = "http://github.com/campaignmonitor/createsend-ruby/"
20
20
  s.require_paths = ["lib"]
21
- s.summary = %q{Wrapper for the CreateSend API v3}
21
+ s.summary = %q{A library which implements the complete functionality of v3 of the createsend API.}
22
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
23
  s.version = CreateSend::VER
24
24
  s.platform = Gem::Platform::RUBY
@@ -1,6 +1,7 @@
1
1
  require 'createsend'
2
2
  require 'json'
3
3
 
4
+ # Represents a campaign and provides associated funtionality.
4
5
  class Campaign
5
6
  attr_reader :campaign_id
6
7
 
@@ -8,8 +9,9 @@ class Campaign
8
9
  @campaign_id = campaign_id
9
10
  end
10
11
 
12
+ # Creates a new campaign for a client.
11
13
  def self.create(client_id, subject, name, from_name, from_email, reply_to, html_url,
12
- text_url, list_ids, segments)
14
+ text_url, list_ids, segment_ids)
13
15
  options = { :body => {
14
16
  :Subject => subject,
15
17
  :Name => name,
@@ -18,12 +20,21 @@ class Campaign
18
20
  :ReplyTo => reply_to,
19
21
  :HtmlUrl => html_url,
20
22
  :TextUrl => text_url,
21
- :ListIDs => list_ids ,
22
- :Segments => segments }.to_json }
23
+ :ListIDs => list_ids,
24
+ :SegmentIDs => segment_ids }.to_json }
23
25
  response = CreateSend.post "/campaigns/#{client_id}.json", options
24
26
  response.parsed_response
25
27
  end
26
-
28
+
29
+ # Sends a preview of this campaign.
30
+ def send_preview(recipients, personalize="fallback")
31
+ options = { :body => {
32
+ :PreviewRecipients => recipients.kind_of?(String) ? [ recipients ] : recipients,
33
+ :Personalize => personalize }.to_json }
34
+ response = post "sendpreview", options
35
+ end
36
+
37
+ # Sends this campaign.
27
38
  def send(confirmation_email, send_date="immediately")
28
39
  options = { :body => {
29
40
  :ConfirmationEmail => confirmation_email,
@@ -31,46 +42,79 @@ class Campaign
31
42
  response = post "send", options
32
43
  end
33
44
 
45
+ # Deletes this campaign.
34
46
  def delete
35
47
  response = CreateSend.delete "/campaigns/#{campaign_id}.json", {}
36
48
  end
37
-
49
+
50
+ # Gets a summary of this campaign
38
51
  def summary
39
52
  response = get "summary", {}
40
53
  Hashie::Mash.new(response)
41
54
  end
42
-
43
- def lists
44
- response = get "lists", {}
45
- response.map{|item| Hashie::Mash.new(item)}
55
+
56
+ # Retrieves the lists and segments to which this campaaign will be (or was) sent.
57
+ def lists_and_segments
58
+ response = get "listsandsegments", {}
59
+ Hashie::Mash.new(response)
46
60
  end
47
-
48
- def segments
49
- # TODO: This needs to be implemented
50
- []
61
+
62
+ # Retrieves the recipients of this campaign.
63
+ def recipients(page=1, page_size=1000, order_field="email", order_direction="asc")
64
+ options = { :query => {
65
+ :page => page,
66
+ :pagesize => page_size,
67
+ :orderfield => order_field,
68
+ :orderdirection => order_direction } }
69
+ response = get 'recipients', options
70
+ Hashie::Mash.new(response)
51
71
  end
52
-
53
- def opens(date)
54
- options = { :query => { :date => date } }
72
+
73
+ # Retrieves the opens for this campaign.
74
+ def opens(date, page=1, page_size=1000, order_field="date", order_direction="asc")
75
+ options = { :query => {
76
+ :date => date,
77
+ :page => page,
78
+ :pagesize => page_size,
79
+ :orderfield => order_field,
80
+ :orderdirection => order_direction } }
55
81
  response = get "opens", options
56
- response.map{|item| Hashie::Mash.new(item)}
82
+ Hashie::Mash.new(response)
57
83
  end
58
-
59
- def clicks(date)
60
- options = { :query => { :date => date } }
84
+
85
+ # Retrieves the subscriber clicks for this campaign.
86
+ def clicks(date, page=1, page_size=1000, order_field="date", order_direction="asc")
87
+ options = { :query => {
88
+ :date => date,
89
+ :page => page,
90
+ :pagesize => page_size,
91
+ :orderfield => order_field,
92
+ :orderdirection => order_direction } }
61
93
  response = get "clicks", options
62
- response.map{|item| Hashie::Mash.new(item)}
94
+ Hashie::Mash.new(response)
63
95
  end
64
-
65
- def unsubscribes(date)
66
- options = { :query => { :date => date } }
96
+
97
+ # Retrieves the unsubscribes for this campaign.
98
+ def unsubscribes(date, page=1, page_size=1000, order_field="date", order_direction="asc")
99
+ options = { :query => {
100
+ :date => date,
101
+ :page => page,
102
+ :pagesize => page_size,
103
+ :orderfield => order_field,
104
+ :orderdirection => order_direction } }
67
105
  response = get "unsubscribes", options
68
- response.map{|item| Hashie::Mash.new(item)}
106
+ Hashie::Mash.new(response)
69
107
  end
70
-
71
- def bounces
72
- response = get "bounces", {}
73
- response.map{|item| Hashie::Mash.new(item)}
108
+
109
+ # Retrieves the bounces for this campaign.
110
+ def bounces(page=1, page_size=1000, order_field="date", order_direction="asc")
111
+ options = { :query => {
112
+ :page => page,
113
+ :pagesize => page_size,
114
+ :orderfield => order_field,
115
+ :orderdirection => order_direction } }
116
+ response = get "bounces", options
117
+ Hashie::Mash.new(response)
74
118
  end
75
119
 
76
120
  private
@@ -1,6 +1,7 @@
1
1
  require 'createsend'
2
2
  require 'json'
3
3
 
4
+ # Represents a client and associated functionality.
4
5
  class Client
5
6
  attr_reader :client_id
6
7
 
@@ -8,6 +9,7 @@ class Client
8
9
  @client_id = client_id
9
10
  end
10
11
 
12
+ # Creates a client.
11
13
  def self.create(company, contact_name, email, timezone, country)
12
14
  options = { :body => {
13
15
  :CompanyName => company,
@@ -18,41 +20,54 @@ class Client
18
20
  CreateSend.post "/clients.json", options
19
21
  end
20
22
 
23
+ # Gets the details of this client.
21
24
  def details
22
25
  response = CreateSend.get "/clients/#{client_id}.json", {}
23
26
  Hashie::Mash.new(response)
24
27
  end
25
28
 
29
+ # Gets the sent campaigns belonging to this client.
26
30
  def campaigns
27
31
  response = get 'campaigns'
28
32
  response.map{|item| Hashie::Mash.new(item)}
29
33
  end
30
34
 
35
+ # Gets the draft campaigns belonging to this client.
31
36
  def drafts
32
37
  response = get 'drafts'
33
38
  response.map{|item| Hashie::Mash.new(item)}
34
39
  end
35
40
 
41
+ # Gets the subscriber lists belonging to this client.
36
42
  def lists
37
43
  response = get 'lists'
38
44
  response.map{|item| Hashie::Mash.new(item)}
39
45
  end
40
46
 
47
+ # Gets the segments belonging to this client.
41
48
  def segments
42
49
  response = get 'segments'
43
50
  response.map{|item| Hashie::Mash.new(item)}
44
51
  end
45
52
 
46
- def suppressionlist
47
- response = get 'suppressionlist'
48
- response.map{|item| Hashie::Mash.new(item)}
53
+ # Gets this client's suppression list.
54
+ def suppressionlist(page=1, page_size=1000, order_field="email", order_direction="asc")
55
+ options = { :query => {
56
+ :page => page,
57
+ :pagesize => page_size,
58
+ :orderfield => order_field,
59
+ :orderdirection => order_direction } }
60
+ response = get 'suppressionlist', options
61
+ Hashie::Mash.new(response)
49
62
  end
50
-
63
+
64
+ # Gets the templates belonging to this client.
51
65
  def templates
52
66
  response = get 'templates'
53
67
  response.map{|item| Hashie::Mash.new(item)}
54
68
  end
55
69
 
70
+ # Sets the basic details for this client.
56
71
  def set_basics(company, contact_name, email, timezone, country)
57
72
  options = { :body => {
58
73
  :CompanyName => company,
@@ -63,6 +78,7 @@ class Client
63
78
  put 'setbasics', options
64
79
  end
65
80
 
81
+ # Sets the access settings for this client.
66
82
  def set_access(username, password, access_level)
67
83
  options = { :body => {
68
84
  :Username => username,
@@ -71,6 +87,7 @@ class Client
71
87
  put 'setaccess', options
72
88
  end
73
89
 
90
+ # Sets the PAYG billing settings for this client.
74
91
  def set_payg_billing(currency, can_purchase_credits, client_pays, markup_percentage,
75
92
  markup_on_delivery=0, markup_per_recipient=0, markup_on_design_spam_test=0)
76
93
  options = { :body => {
@@ -84,6 +101,7 @@ class Client
84
101
  put 'setpaygbilling', options
85
102
  end
86
103
 
104
+ # Sets the monthly billing settings for this client.
87
105
  def set_monthly_billing(currency, can_purchase_credits, client_pays, markup_percentage)
88
106
  options = { :body => {
89
107
  :Currency => currency,
@@ -93,6 +111,7 @@ class Client
93
111
  put 'setmonthlybilling', options
94
112
  end
95
113
 
114
+ # Deletes this client.
96
115
  def delete
97
116
  CreateSend.delete "/clients/#{client_id}.json", {}
98
117
  end
@@ -17,14 +17,18 @@ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
17
17
  require 'client'
18
18
  require 'campaign'
19
19
  require 'list'
20
+ require 'segment'
20
21
  require 'subscriber'
21
22
  require 'template'
22
23
 
24
+ # Represents a CreateSend API error and contains specific data about the error.
23
25
  class CreateSendError < StandardError
24
26
  attr_reader :data
25
27
  def initialize(data)
26
28
  @data = data
27
- super "The CreateSend API responded with the following error - #{@data.Code}: #{@data.Message}"
29
+ # @data should contain Code, Message and optionally ResultData
30
+ extra = @data.ResultData ? "\nExtra result data: #{@data.ResultData}" : ""
31
+ super "The CreateSend API responded with the following error - #{@data.Code}: #{@data.Message}#{extra}"
28
32
  end
29
33
  end
30
34
 
@@ -35,21 +39,24 @@ class Unauthorized < ClientError; end
35
39
  class NotFound < ClientError; end
36
40
  class Unavailable < StandardError; end
37
41
 
42
+ # Provides high level CreateSend functionality/data you'll probably need.
38
43
  class CreateSend
39
44
  include HTTParty
40
- headers 'Content-Type' => 'application/json'
45
+
46
+ VER = "0.0.2" unless defined?(CreateSend::VER)
47
+ headers({ 'User-Agent' => "createsend-ruby-#{CreateSend::VER}", 'Content-Type' => 'application/json' })
41
48
  base_uri CreateSendOptions['base_uri']
42
49
  basic_auth CreateSendOptions['api_key'], 'x'
43
-
44
- VER = "0.0.1" unless defined?(CreateSend::VER)
45
-
50
+
51
+ # Sets the API key which will be used to make calls to the CreateSend API.
46
52
  def self.api_key(api_key=nil)
47
53
  return @@api_key unless api_key
48
54
  CreateSendOptions['api_key'] = api_key
49
55
  @@api_key = api_key
50
56
  basic_auth @@api_key, 'x'
51
57
  end
52
-
58
+
59
+ # Gets your CreateSend API key, given your site url, username and password.
53
60
  def apikey(site_url, username, password)
54
61
  site_url = CGI.escape(site_url)
55
62
  self.class.basic_auth username, password
@@ -59,21 +66,25 @@ class CreateSend
59
66
  Hashie::Mash.new(response)
60
67
  end
61
68
 
69
+ # Gets your clients.
62
70
  def clients
63
71
  response = CreateSend.get('/clients.json')
64
72
  response.map{|item| Hashie::Mash.new(item)}
65
73
  end
66
74
 
75
+ # Gets valid countries.
67
76
  def countries
68
77
  response = CreateSend.get('/countries.json')
69
78
  response.parsed_response
70
79
  end
71
80
 
81
+ # Gets the current date in your account's timezone.
72
82
  def systemdate
73
83
  response = CreateSend.get('/systemdate.json')
74
84
  Hashie::Mash.new(response)
75
85
  end
76
86
 
87
+ # Gets valid timezones.
77
88
  def timezones
78
89
  response = CreateSend.get('/timezones.json')
79
90
  response.parsed_response
@@ -84,7 +95,7 @@ class CreateSend
84
95
  def self.put(*args); handle_response super end
85
96
  def self.delete(*args); handle_response super end
86
97
 
87
- def self.handle_response(response)
98
+ def self.handle_response(response) # :nodoc:
88
99
  case response.code
89
100
  when 400
90
101
  raise BadRequest.new(Hashie::Mash.new response)
@@ -1,6 +1,7 @@
1
1
  require 'createsend'
2
2
  require 'json'
3
3
 
4
+ # Represents a subscriber list and associated functionality.
4
5
  class List
5
6
  attr_reader :list_id
6
7
 
@@ -8,6 +9,7 @@ class List
8
9
  @list_id = list_id
9
10
  end
10
11
 
12
+ # Creates a new list for a client.
11
13
  def self.create(client_id, title, unsubscribe_page, confirmed_opt_in, confirmation_success_page)
12
14
  options = { :body => {
13
15
  :Title => title,
@@ -18,10 +20,12 @@ class List
18
20
  response.parsed_response
19
21
  end
20
22
 
23
+ # Deletes this list.
21
24
  def delete
22
25
  response = CreateSend.delete "/lists/#{list_id}.json", {}
23
26
  end
24
-
27
+
28
+ # Creates a new custom field for this list.
25
29
  def create_custom_field(field_name, data_type, options=[])
26
30
  options = { :body => {
27
31
  :FieldName => field_name,
@@ -31,44 +35,82 @@ class List
31
35
  response.parsed_response
32
36
  end
33
37
 
38
+ # Deletes a custom field associated with this list.
34
39
  def delete_custom_field(custom_field_key)
35
40
  custom_field_key = CGI.escape(custom_field_key)
36
41
  response = CreateSend.delete "/lists/#{list_id}/customfields/#{custom_field_key}.json", {}
37
42
  end
38
-
43
+
44
+ # Updates the options of a multi-optioned custom field on this list.
45
+ def update_custom_field_options(custom_field_key, new_options, keep_existing_options)
46
+ custom_field_key = CGI.escape(custom_field_key)
47
+ options = { :body => {
48
+ :Options => new_options,
49
+ :KeepExistingOptions => keep_existing_options }.to_json }
50
+ response = put "customfields/#{custom_field_key}/options", options
51
+ end
52
+
53
+ # Gets the details of this list.
39
54
  def details
40
55
  response = CreateSend.get "/lists/#{list_id}.json", {}
41
56
  Hashie::Mash.new(response)
42
57
  end
43
-
58
+
59
+ # Gets the custom fields for this list.
44
60
  def custom_fields
45
61
  response = get "customfields"
46
62
  response.map{|item| Hashie::Mash.new(item)}
47
63
  end
48
-
64
+
65
+ # Gets the segments for this list.
66
+ def segments
67
+ response = get "segments"
68
+ response.map{|item| Hashie::Mash.new(item)}
69
+ end
70
+
71
+ # Gets the stats for this list.
49
72
  def stats
50
73
  response = get "stats"
51
74
  Hashie::Mash.new(response)
52
75
  end
53
76
 
54
- def active(date)
55
- options = { :query => { :date => date } }
77
+ # Gets the active subscribers for this list.
78
+ def active(date, page=1, page_size=1000, order_field="email", order_direction="asc")
79
+ options = { :query => {
80
+ :date => date,
81
+ :page => page,
82
+ :pagesize => page_size,
83
+ :orderfield => order_field,
84
+ :orderdirection => order_direction } }
56
85
  response = get "active", options
57
- response.map{|item| Hashie::Mash.new(item)}
86
+ Hashie::Mash.new(response)
58
87
  end
59
88
 
60
- def bounced(date)
61
- options = { :query => { :date => date } }
89
+ # Gets the bounced subscribers for this list.
90
+ def bounced(date, page=1, page_size=1000, order_field="email", order_direction="asc")
91
+ options = { :query => {
92
+ :date => date,
93
+ :page => page,
94
+ :pagesize => page_size,
95
+ :orderfield => order_field,
96
+ :orderdirection => order_direction } }
62
97
  response = get "bounced", options
63
- response.map{|item| Hashie::Mash.new(item)}
98
+ Hashie::Mash.new(response)
64
99
  end
65
100
 
66
- def unsubscribed(date)
67
- options = { :query => { :date => date } }
101
+ # Gets the unsubscribed subscribers for this list.
102
+ def unsubscribed(date, page=1, page_size=1000, order_field="email", order_direction="asc")
103
+ options = { :query => {
104
+ :date => date,
105
+ :page => page,
106
+ :pagesize => page_size,
107
+ :orderfield => order_field,
108
+ :orderdirection => order_direction } }
68
109
  response = get "unsubscribed", options
69
- response.map{|item| Hashie::Mash.new(item)}
110
+ Hashie::Mash.new(response)
70
111
  end
71
112
 
113
+ # Updates this list.
72
114
  def update(title, unsubscribe_page, confirmed_opt_in, confirmation_success_page)
73
115
  options = { :body => {
74
116
  :Title => title,