createsend 2.5.1 → 3.0.0

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.
@@ -1,33 +1,33 @@
1
- require 'createsend'
2
- require 'json'
3
-
4
1
  module CreateSend
5
2
  # Represents an administrator and associated functionality.
6
- class Administrator
3
+ class Administrator < CreateSend
7
4
  attr_reader :email_address
8
5
 
9
- def initialize(email_address)
6
+ def initialize(auth, email_address)
10
7
  @email_address = email_address
8
+ super
11
9
  end
12
10
 
13
- # Gets an adminsitrator by email address.
14
- def self.get(email_address)
11
+ # Gets an administrator by email address.
12
+ def self.get(auth, email_address)
15
13
  options = { :query => { :email => email_address } }
16
- response = CreateSend.get "/admins.json", options
14
+ cs = CreateSend.new auth
15
+ response = cs.cs_get "/admins.json", options
17
16
  Hashie::Mash.new(response)
18
17
  end
19
18
 
20
- # Adds an adminstrator to the account
21
- def self.add(email_address, name)
19
+ # Adds an administrator to the account.
20
+ def self.add(auth, email_address, name)
22
21
  options = { :body => {
23
22
  :EmailAddress => email_address,
24
23
  :Name => name
25
24
  }.to_json }
26
- response = CreateSend.post "/admins.json", options
25
+ cs = CreateSend.new auth
26
+ response = cs.cs_post "/admins.json", options
27
27
  Hashie::Mash.new(response)
28
28
  end
29
29
 
30
- # Updates the administator details
30
+ # Updates the administator details.
31
31
  def update(new_email_address, name)
32
32
  options = {
33
33
  :query => { :email => @email_address },
@@ -35,15 +35,15 @@ module CreateSend
35
35
  :EmailAddress => new_email_address,
36
36
  :Name => name
37
37
  }.to_json }
38
- CreateSend.put '/admins.json', options
38
+ put '/admins.json', options
39
39
  # Update @email_address, so this object can continue to be used reliably
40
40
  @email_address = new_email_address
41
41
  end
42
42
 
43
- # deletes this administrator from the account
43
+ # Deletes this administrator from the account.
44
44
  def delete
45
45
  options = { :query => { :email => @email_address } }
46
- CreateSend.delete '/admins.json', options
46
+ super '/admins.json', options
47
47
  end
48
48
  end
49
49
  end
@@ -1,13 +1,11 @@
1
- require 'createsend'
2
- require 'json'
3
-
4
1
  module CreateSend
5
2
  # Represents a campaign and provides associated funtionality.
6
- class Campaign
3
+ class Campaign < CreateSend
7
4
  attr_reader :campaign_id
8
5
 
9
- def initialize(campaign_id)
6
+ def initialize(auth, campaign_id)
10
7
  @campaign_id = campaign_id
8
+ super
11
9
  end
12
10
 
13
11
  # Creates a new campaign for a client.
@@ -26,7 +24,7 @@ module CreateSend
26
24
  # which the campaign will be sent.
27
25
  # segment_ids - Array of Strings representing the IDs of the segments to
28
26
  # which the campaign will be sent.
29
- def self.create(client_id, subject, name, from_name, from_email,
27
+ def self.create(auth, client_id, subject, name, from_name, from_email,
30
28
  reply_to, html_url, text_url, list_ids, segment_ids)
31
29
  options = { :body => {
32
30
  :Subject => subject,
@@ -38,7 +36,8 @@ module CreateSend
38
36
  :TextUrl => text_url,
39
37
  :ListIDs => list_ids,
40
38
  :SegmentIDs => segment_ids }.to_json }
41
- response = CreateSend.post "/campaigns/#{client_id}.json", options
39
+ cs = CreateSend.new auth
40
+ response = cs.post "/campaigns/#{client_id}.json", options
42
41
  response.parsed_response
43
42
  end
44
43
 
@@ -60,7 +59,7 @@ module CreateSend
60
59
  # editable areas of the template. See documentation at
61
60
  # campaignmonitor.com/api/campaigns/#creating_a_campaign_from_template
62
61
  # for full details of template content format.
63
- def self.create_from_template(client_id, subject, name, from_name,
62
+ def self.create_from_template(auth, client_id, subject, name, from_name,
64
63
  from_email, reply_to, list_ids, segment_ids, template_id,
65
64
  template_content)
66
65
  options = { :body => {
@@ -73,7 +72,8 @@ module CreateSend
73
72
  :SegmentIDs => segment_ids,
74
73
  :TemplateID => template_id,
75
74
  :TemplateContent => template_content }.to_json }
76
- response = CreateSend.post(
75
+ cs = CreateSend.new auth
76
+ response = cs.post(
77
77
  "/campaigns/#{client_id}/fromtemplate.json", options)
78
78
  response.parsed_response
79
79
  end
@@ -103,7 +103,7 @@ module CreateSend
103
103
 
104
104
  # Deletes this campaign.
105
105
  def delete
106
- response = CreateSend.delete "/campaigns/#{campaign_id}.json", {}
106
+ response = super "/campaigns/#{campaign_id}.json", {}
107
107
  end
108
108
 
109
109
  # Gets a summary of this campaign
@@ -140,76 +140,58 @@ module CreateSend
140
140
  # Retrieves the opens for this campaign.
141
141
  def opens(date="", page=1, page_size=1000, order_field="date",
142
142
  order_direction="asc")
143
- options = { :query => {
144
- :date => date,
145
- :page => page,
146
- :pagesize => page_size,
147
- :orderfield => order_field,
148
- :orderdirection => order_direction } }
149
- response = get "opens", options
150
- Hashie::Mash.new(response)
143
+ paged_result_by_date("opens", date, page, page_size, order_field,
144
+ order_direction)
151
145
  end
152
146
 
153
147
  # Retrieves the subscriber clicks for this campaign.
154
148
  def clicks(date="", page=1, page_size=1000, order_field="date",
155
149
  order_direction="asc")
156
- options = { :query => {
157
- :date => date,
158
- :page => page,
159
- :pagesize => page_size,
160
- :orderfield => order_field,
161
- :orderdirection => order_direction } }
162
- response = get "clicks", options
163
- Hashie::Mash.new(response)
150
+ paged_result_by_date("clicks", date, page, page_size, order_field,
151
+ order_direction)
164
152
  end
165
153
 
166
154
  # Retrieves the unsubscribes for this campaign.
167
155
  def unsubscribes(date="", page=1, page_size=1000, order_field="date",
168
156
  order_direction="asc")
169
- options = { :query => {
170
- :date => date,
171
- :page => page,
172
- :pagesize => page_size,
173
- :orderfield => order_field,
174
- :orderdirection => order_direction } }
175
- response = get "unsubscribes", options
176
- Hashie::Mash.new(response)
157
+ paged_result_by_date("unsubscribes", date, page, page_size, order_field,
158
+ order_direction)
177
159
  end
178
160
 
179
161
  # Retrieves the spam complaints for this campaign.
180
162
  def spam(date="", page=1, page_size=1000, order_field="date",
181
163
  order_direction="asc")
182
- options = { :query => {
183
- :date => date,
184
- :page => page,
185
- :pagesize => page_size,
186
- :orderfield => order_field,
187
- :orderdirection => order_direction } }
188
- response = get "spam", options
189
- Hashie::Mash.new(response)
164
+ paged_result_by_date("spam", date, page, page_size, order_field,
165
+ order_direction)
190
166
  end
191
167
 
192
168
  # Retrieves the bounces for this campaign.
193
169
  def bounces(date="", page=1, page_size=1000, order_field="date",
194
170
  order_direction="asc")
171
+ paged_result_by_date("bounces", date, page, page_size, order_field,
172
+ order_direction)
173
+ end
174
+
175
+ private
176
+
177
+ def paged_result_by_date(resource, date, page, page_size, order_field,
178
+ order_direction)
195
179
  options = { :query => {
196
180
  :date => date,
197
181
  :page => page,
198
182
  :pagesize => page_size,
199
183
  :orderfield => order_field,
200
184
  :orderdirection => order_direction } }
201
- response = get "bounces", options
185
+ response = get resource, options
202
186
  Hashie::Mash.new(response)
203
187
  end
204
188
 
205
- private
206
-
207
189
  def get(action, options = {})
208
- CreateSend.get uri_for(action), options
190
+ super uri_for(action), options
209
191
  end
210
192
 
211
193
  def post(action, options = {})
212
- CreateSend.post uri_for(action), options
194
+ super uri_for(action), options
213
195
  end
214
196
 
215
197
  def uri_for(action)
@@ -1,27 +1,26 @@
1
- require 'createsend'
2
- require 'json'
3
-
4
1
  module CreateSend
5
2
  # Represents a client and associated functionality.
6
- class Client
3
+ class Client < CreateSend
7
4
  attr_reader :client_id
8
5
 
9
- def initialize(client_id)
6
+ def initialize(auth, client_id)
10
7
  @client_id = client_id
8
+ super
11
9
  end
12
10
 
13
11
  # Creates a client.
14
- def self.create(company, timezone, country)
12
+ def self.create(auth, company, timezone, country)
15
13
  options = { :body => {
16
14
  :CompanyName => company,
17
15
  :TimeZone => timezone,
18
16
  :Country => country }.to_json }
19
- CreateSend.post "/clients.json", options
17
+ cs = CreateSend.new auth
18
+ cs.post "/clients.json", options
20
19
  end
21
20
 
22
21
  # Gets the details of this client.
23
22
  def details
24
- response = CreateSend.get "/clients/#{client_id}.json", {}
23
+ response = cs_get "/clients/#{client_id}.json", {}
25
24
  Hashie::Mash.new(response)
26
25
  end
27
26
 
@@ -179,21 +178,21 @@ module CreateSend
179
178
 
180
179
  # Deletes this client.
181
180
  def delete
182
- CreateSend.delete "/clients/#{client_id}.json", {}
181
+ super "/clients/#{client_id}.json", {}
183
182
  end
184
183
 
185
184
  private
186
185
 
187
186
  def get(action, options = {})
188
- CreateSend.get uri_for(action), options
187
+ super uri_for(action), options
189
188
  end
190
189
 
191
190
  def post(action, options = {})
192
- CreateSend.post uri_for(action), options
191
+ super uri_for(action), options
193
192
  end
194
193
 
195
194
  def put(action, options = {})
196
- CreateSend.put uri_for(action), options
195
+ super uri_for(action), options
197
196
  end
198
197
 
199
198
  def uri_for(action)
@@ -0,0 +1,245 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+ require 'httparty'
4
+ require 'hashie'
5
+ require 'json'
6
+
7
+ module CreateSend
8
+
9
+ # Represents a CreateSend API error. Contains specific data about the error.
10
+ class CreateSendError < StandardError
11
+ attr_reader :data
12
+ def initialize(data)
13
+ @data = data
14
+ # @data should contain Code, Message and optionally ResultData
15
+ extra = @data.ResultData ? "\nExtra result data: #{@data.ResultData}" : ""
16
+ super "The CreateSend API responded with the following error"\
17
+ " - #{@data.Code}: #{@data.Message}#{extra}"
18
+ end
19
+ end
20
+
21
+ # Raised for HTTP response codes of 400...500
22
+ class ClientError < StandardError; end
23
+ # Raised for HTTP response codes of 500...600
24
+ class ServerError < StandardError; end
25
+ # Raised for HTTP response code of 400
26
+ class BadRequest < CreateSendError; end
27
+ # Raised for HTTP response code of 401
28
+ class Unauthorized < CreateSendError; end
29
+ # Raised for HTTP response code of 404
30
+ class NotFound < ClientError; end
31
+
32
+ # Raised for HTTP response code of 401, specifically when an OAuth token
33
+ # has expired (Code: 121, Message: 'Expired OAuth Token')
34
+ class ExpiredOAuthToken < Unauthorized; end
35
+
36
+ # Provides high level CreateSend functionality/data you'll probably need.
37
+ class CreateSend
38
+ include HTTParty
39
+ attr_reader :auth_details
40
+
41
+ # Get the authorization URL for your application, given the application's
42
+ # client_id, redirect_uri, scope, and optional state data.
43
+ def self.authorize_url(client_id, redirect_uri, scope, state=nil)
44
+ qs = "client_id=#{CGI.escape(client_id.to_s)}"
45
+ qs << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}"
46
+ qs << "&scope=#{CGI.escape(scope.to_s)}"
47
+ qs << "&state=#{CGI.escape(state.to_s)}" if state
48
+ "#{@@oauth_base_uri}?#{qs}"
49
+ end
50
+
51
+ # Exchange a provided OAuth code for an OAuth access token, 'expires in'
52
+ # value and refresh token.
53
+ def self.exchange_token(client_id, client_secret, redirect_uri, code)
54
+ body = "grant_type=authorization_code"
55
+ body << "&client_id=#{CGI.escape(client_id.to_s)}"
56
+ body << "&client_secret=#{CGI.escape(client_secret.to_s)}"
57
+ body << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}"
58
+ body << "&code=#{CGI.escape(code.to_s)}"
59
+ options = {:body => body}
60
+ response = HTTParty.post(@@oauth_token_uri, options)
61
+ if response.has_key? 'error' and response.has_key? 'error_description'
62
+ err = "Error exchanging code for access token: "
63
+ err << "#{response['error']} - #{response['error_description']}"
64
+ raise err
65
+ end
66
+ r = Hashie::Mash.new(response)
67
+ [r.access_token, r.expires_in, r.refresh_token]
68
+ end
69
+
70
+ def initialize(*args)
71
+ if args.size > 0
72
+ auth args.first # Expect auth details as first argument
73
+ end
74
+ end
75
+
76
+ # Deals with an unfortunate situation where responses aren't valid json.
77
+ class Parser::DealWithCreateSendInvalidJson < HTTParty::Parser
78
+ # The createsend API returns an ID as a string when a 201 Created
79
+ # response is returned. Unfortunately this is invalid json.
80
+ def parse
81
+ begin
82
+ super
83
+ rescue MultiJson::DecodeError => e
84
+ body[1..-2] # Strip surrounding quotes and return as is.
85
+ end
86
+ end
87
+ end
88
+ parser Parser::DealWithCreateSendInvalidJson
89
+ @@base_uri = "https://api.createsend.com/api/v3"
90
+ @@oauth_base_uri = "https://api.createsend.com/oauth"
91
+ @@oauth_token_uri = "#{@@oauth_base_uri}/token"
92
+ headers({
93
+ 'User-Agent' => "createsend-ruby-#{VERSION}",
94
+ 'Content-Type' => 'application/json; charset=utf-8',
95
+ 'Accept-Encoding' => 'gzip, deflate' })
96
+ base_uri @@base_uri
97
+
98
+ # Authenticate using either OAuth or an API key.
99
+ def auth(auth_details)
100
+ @auth_details = auth_details
101
+ end
102
+
103
+ # Refresh the current OAuth token using the current refresh token.
104
+ def refresh_token
105
+ if not @auth_details or
106
+ not @auth_details.has_key? :refresh_token or
107
+ not @auth_details[:refresh_token]
108
+ raise '@auth_details[:refresh_token] does not contain a refresh token.'
109
+ end
110
+
111
+ options = {
112
+ :body => "grant_type=refresh_token&refresh_token=#{@auth_details[:refresh_token]}" }
113
+ response = HTTParty.post(@@oauth_token_uri, options)
114
+ r = Hashie::Mash.new(response)
115
+ auth({
116
+ :access_token => r.access_token,
117
+ :refresh_token => r.refresh_token})
118
+ [r.access_token, r.expires_in, r.refresh_token]
119
+ end
120
+
121
+ # Gets your CreateSend API key, given your site url, username and password.
122
+ def apikey(site_url, username, password)
123
+ site_url = CGI.escape(site_url)
124
+ options = {:basic_auth => {:username => username, :password => password}}
125
+ response = get("/apikey.json?SiteUrl=#{site_url}", options)
126
+ result = Hashie::Mash.new(response)
127
+ auth({:api_key => result.ApiKey}) if not @auth_details
128
+ result
129
+ end
130
+
131
+ # Gets your clients.
132
+ def clients
133
+ response = get('/clients.json')
134
+ response.map{|item| Hashie::Mash.new(item)}
135
+ end
136
+
137
+ # Get your billing details.
138
+ def billing_details
139
+ response = get('/billingdetails.json')
140
+ Hashie::Mash.new(response)
141
+ end
142
+
143
+ # Gets valid countries.
144
+ def countries
145
+ response = get('/countries.json')
146
+ response.parsed_response
147
+ end
148
+
149
+ # Gets the current date in your account's timezone.
150
+ def systemdate
151
+ response = get('/systemdate.json')
152
+ Hashie::Mash.new(response)
153
+ end
154
+
155
+ # Gets valid timezones.
156
+ def timezones
157
+ response = get('/timezones.json')
158
+ response.parsed_response
159
+ end
160
+
161
+ # Gets the administrators for the account.
162
+ def administrators
163
+ response = get('/admins.json')
164
+ response.map{|item| Hashie::Mash.new(item)}
165
+ end
166
+
167
+ # Gets the primary contact for the account.
168
+ def get_primary_contact
169
+ response = get('/primarycontact.json')
170
+ Hashie::Mash.new(response)
171
+ end
172
+
173
+ # Set the primary contect for the account.
174
+ def set_primary_contact(email)
175
+ options = { :query => { :email => email } }
176
+ response = put("/primarycontact.json", options)
177
+ Hashie::Mash.new(response)
178
+ end
179
+
180
+ def get(*args)
181
+ args = add_auth_details_to_options(args)
182
+ handle_response CreateSend.get(*args)
183
+ end
184
+ alias_method :cs_get, :get
185
+
186
+ def post(*args)
187
+ args = add_auth_details_to_options(args)
188
+ handle_response CreateSend.post(*args)
189
+ end
190
+ alias_method :cs_post, :post
191
+
192
+ def put(*args)
193
+ args = add_auth_details_to_options(args)
194
+ handle_response CreateSend.put(*args)
195
+ end
196
+ alias_method :cs_put, :put
197
+
198
+ def delete(*args)
199
+ args = add_auth_details_to_options(args)
200
+ handle_response CreateSend.delete(*args)
201
+ end
202
+ alias_method :cs_delete, :delete
203
+
204
+ def add_auth_details_to_options(args)
205
+ if @auth_details
206
+ options = {}
207
+ if args.size > 1
208
+ options = args[1]
209
+ end
210
+ if @auth_details.has_key? :access_token
211
+ options[:headers] = {
212
+ "Authorization" => "Bearer #{@auth_details[:access_token]}" }
213
+ elsif @auth_details.has_key? :api_key
214
+ if not options.has_key? :basic_auth
215
+ options[:basic_auth] = {
216
+ :username => @auth_details[:api_key], :password => 'x' }
217
+ end
218
+ end
219
+ args[1] = options
220
+ end
221
+ args
222
+ end
223
+
224
+ def handle_response(response) # :nodoc:
225
+ case response.code
226
+ when 400
227
+ raise BadRequest.new(Hashie::Mash.new response)
228
+ when 401
229
+ data = Hashie::Mash.new(response)
230
+ if data.Code == 121
231
+ raise ExpiredOAuthToken.new(data)
232
+ end
233
+ raise Unauthorized.new(data)
234
+ when 404
235
+ raise NotFound.new
236
+ when 400...500
237
+ raise ClientError.new
238
+ when 500...600
239
+ raise ServerError.new
240
+ else
241
+ response
242
+ end
243
+ end
244
+ end
245
+ end