createsend 2.5.1 → 3.0.0

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