createsend 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,